Professional Documents
Culture Documents
1. Od problemu do programu
Codziennie spotykasz się z różnymi sytuacjami problemowymi. W niektórych z nich, np. przy wiązaniu
sznurówek, działasz automatycznie. Gdy jednak robisz coś po raz pierwszy, postępujesz krok po kroku według
ustalonego przepisu. Można podać wiele przykładów problemów, których rozwiązanie polega na wykonywaniu
ciągu kolejnych instrukcji. W tym temacie poznasz podstawy algorytmicznego rozwiązania problemów.
Cele lekcji
Na początku rozwiązywania problemu z wykorzystaniem komputera musisz określić dane początkowe i efekt
(wynik), który chcesz osiągnąć.
Trzeba nauczyć się wyróżniać kroki algorytmu, a w ich opisie stosować operacje, które będzie można potem
zapisać w języku programowania. Kod źródłowy programu komputerowego to właśnie zapis algorytmu w języku
programowania.
Od problemu do algorytmu
Omówimy teraz kilka przykładów problemów. Dla każdego z nich przedstawimy algorytm jego rozwiązania.
Problem 1
Jak zapleść warkocz klasyczny?
Wyobraź sobie, że musisz wytłumaczyć komuś, jak zapleść warkocz klasyczny. Zapewne najłatwiej będzie ci
pokazać to na przykładzie. Jeśli nie masz takiej możliwości, musisz precyzyjnie opisać sposób postępowania.
Algorytm zaplatania warkocza może wyglądać następująco.
KROK 3: Przełóż lewe pasmo nad środkowym . Teraz to pasmo staje się środkowym
KROK 4: Przełóż prawe pasmo nad środkowym. Teraz to pasmo staje się środkowym
Ćwiczenie 1
Odpowiedz na pytania dotyczące podanej instrukcji zaplatania warkocza klasycznego.
Problem 2
Mnożenie liczb sposobem pisemnym
Mnożenia liczb sposobem pisemnym uczyliście się w szkole podstawowej. Wróćmy teraz do tego algorytmu i
przyjrzyjmy mu się bliżej.
Załóżmy, że chcemy pomnożyć dwie liczby całkowite dodatnie, przynajmniej dwucyfrowe, np.: 2782 i 213.
Mnożenie pisemne wyglądałoby tak jak poniżej.
Istotą zastosowania algorytmu mnożenia liczb a i b jest utworzenie sum pośrednich (przesuniętych iloczynów
cząstkowych), z których każda reprezentuje iloczyn liczb a przez jedną z cyfr liczby b. wartości te są
odpowiednio przesuwane w lewo i następnie dodawane.
Zapiszemy teraz algorytm pisemnego mnożenie dwóch liczb całkowitych dodatnich, przynajmniej
dwucyfrowych.
Specyfikacja problemu – określenie danych, wyniku oraz związku między danymi i wynikiem.
Specyfikacja:
Krok 2: Zapisz liczbę b poniżej liczby a tak, żeby jej cyfry jedności, dziesiątek,
setek itd. znajdowały się odpowiednio pod cyframi jedności, dziesiątek, setek itd.
liczby a
Krok 3: Dla każdej z cyfr liczby b , począwszy od cyfry jedności, traktowanych jako
liczby jednocyfrowe, wykonaj kroki 4 i 5
Krok 5: jeśli iloczyn jest pierwszym cząstkowym iloczynem, to zapisz go poniżej liczby
b (jedności pod jednościami , dziesiątki pod dziesiątkami itd.). Kolejne
iloczyny zapisuj z odpowiednim przesunięciem w lewo, tj. cyfrę jedności
iloczynu zapisz pod cyfrą dziesiątek poprzedniego iloczynu, cyfrę dziesiątek
iloczynu zapisz pod cyfrą setek poprzedniego iloczynu itd.
Zwróć uwagę, że niektóre kroki wymagają rozwiązania mniejszych problemów (podproblemów). Z taką sytuacja
mamy do czynienia np. w kroku 3 (wyodrębnianie cyfr liczby), krok 4 (mnożenie pisemne przez liczbę
jednocyfrową ) i krok 6 (pisemne dodawanie liczb całkowitych dodatnich). W przyszłości często będziesz się
spotykał z takim podejściem: dzielenie złożonego problemu na podproblemy.
Problem 3
Podział liczby na cyfry
Teraz przedstawimy algorytm wypisujący kolejne cyfry liczby całkowitej dodatniej, zaczynając od cyfry jedności
(od prawej do lewej).
Specyfikacja:
Do wykonania zadania wykorzystamy dzielenie przez 10. Weźmy przykładową liczbę 213. Po podzieleniu jej
przez 10 otrzymamy część całkowitą 21 oraz resztę 3, która jest wyodrębnioną cyfrą jedności.
21 wykorzystamy do wyodrębnienia cyfry dziesiątek – ponownie wykonujemy dzielenie przez 10. Wynik
kolejnych działań dla liczby 213 przedstawia tabela poniżej.
Ćwiczenie 2
Zmień w powyższym algorytmie dzielenie przez 10 na dzielenie przez 2. Ustal, co będzie wynikiem.
Problem 4
Podział na równoliczne grupy
Czasami zachodzi potrzeba podziału grupy osób na mniejsze równoliczne grupy, np. podczas treningów
piłkarskich (gry kontrolne) czy na lekcjach WF. Chcemy podać algorytm, po którego wykonaniu dowiemy się, na
ile sposobów można to zrobić. Może się zdarzyć, że grupy nie da się tak podzielić.
Przyjmijmy, że chcemy się dowiedzieć , na ile sposobów można podzielić grupę n osób na równoliczne, co
najmniej dwuosobowe zespoły. Rozwiązanie zadania sprowadza się do policzenia, ile dzielników właściwych
większych od 1 ma dana liczba.
Dzielniki właściwe – to dzielniki mniejsze od danej liczby. Każda liczba całkowita większa od 1 ma
przynajmniej jeden dzielnik właściwy – liczbę 1.
Specyfikacja:
Zmienna - to miejsce przechowywania danych, które ma nazwę i w którym można zapisać pewną
wartość. Do wartości odwołujemy się za pomocą nazwy zmiennej.
Największym możliwym dzielnikiem właściwym liczby n jest jej połowa (dla liczby parzystej to dokładnie jej
połowa, dla nieparzystej – liczba mniejsza niż połowa). Dlatego w kroku 2 podanego poniżej algorytmu
zliczającego dzielniki właściwe przeglądamy liczby od 2 do połowy n.
Algorytm – wersja 1:
Krok 1: Ustaw licznik_dzielników na 0
Krok 3: Jeśli reszta z dzielenia n przez liczbę jest równa zero, powiększ wartość
zmiennej licznik_dzielników o 1
Zapiszmy inny algorytm rozwiązujący ten sam problem. Zwróć uwagę, że gdy znajdziemy jeden dzielnik,
automatycznie znaleźliśmy drugi.
Jeśli liczba n dzieli się bez reszty przez liczbę d1, to dzieli się także przez liczbę
d2 = n : d1 (n = d1 ⸳ d2).
Należy tylko uważać na sytuację, gdy n jest kwadratem jakiejś liczby, czyli d1 = d2. Wówczas trzeba zwiększyć
wartość zmiennej liczbnik_dzielników o jeden, a nie o dwa
Algorytm – wersja 2:
Krok 1: Ustaw licznik_dzielników na 0
Ćwiczenie 3
Ile operacji dzielenia jest wykonywanych w każdym z algorytmów zliczających dzielniki właściwe danej liczby
większej od 1?
Często można podać różne algorytmy rozwiązania danego problemu, różniące się m. in. liczbą wykonywanych
operacji.
Cechy algorytmu
1. Lista kroków
2. Algorytm graficzny – schemat blokowy
3. Pseudokod
4. Zapis w postaci programu
Ćwiczenie 4
Zapisz w postaci listy kroków algorytm opisujący, jak zawiązać sobie krawat. Jeśli nie umiesz wiązać krawata,
możesz np. poszukać filmu instruktażowego w Internecie.
Ćwiczenie 5
Przedstaw w postaci schematu blokowego jeden z algorytmów obliczających dla danej liczby całkowitej
dodatniej liczbę jej dzielników właściwych większy od 1.
Pseudokod - w odróżnieniu od schematu blokowego nie ma ściśle określonych reguł składniowych, ale
charakteryzuje się prostotą i czytelnością. Pseudokod zachowuje strukturę charakterystyczną dal kodu
zapisanego w języku programowania. Ze względu na te cechy kolejne algorytmy przeważnie będą zapisywane w
pseudokodzie.
Operacja wyznaczania reszty z dzielenia jest bardzo ważna i często wykorzystywana w algorytmice. W różnych
językach programowania jest różnie oznaczana, w pseudokodzie najczęściej oznaczamy ją skrótem mod (od
słowa „modulo”).
Wróćmy do drugiego z algorytmów obliczających dla całkowitej liczby dodatniej n liczbę jej dzielników
właściwych większych od 1.
licznik ← 0
dzielnik ← 0
dzielnik ← dzielnik + 1
wypisz licznik
Zwróć uwagę na wcięcia w pseudokodzie. Nie tylko poprawiają one czytelność zapisu, ale też określają
kolejność wykonywania instrukcji. W powyższym przykładzie wskazują instrukcje, które są powtarzane.
Ćwiczenie 6
Zapisz w postaci pseudokodu algorytm wypisujący dzielniki właściwe liczby całkowitej dodatniej.
Warto zastanowić się, jaki niezbędny zestaw instrukcji potrzebny jest do zapisu algorytmów. Powinniśmy mieć
do dyspozycji pewne operacje elementarne – np. podstawowe działania arytmetyczne, operacje logiczne czy
instrukcję przypisania wartości zmiennej. Musimy mieć również możliwość ustalania kolejności wykonywania
operacji, a więc dysponować pewnymi instrukcjami sterującymi.
Instrukcje A i B mogą być nie tylko operacjami elementarnymi, lecz także instrukcjami sterującymi lub
instrukcją złożoną – sekwencyjnym ciągiem instrukcji.
Od algorytmu do programu w C++
Teraz zajmiemy się zapisem algorytmów w języku programowania, czyli tworzeniem kodów źródłowych
programów komputerowych. Aby komputer mógł wykonać napisany przez nas program, kod musi zostać
przetłumaczony na język wewnętrzny procesora (kod maszynowy).
1 Kompilatory – tłumaczą cały kod źródłowy, po zakończeniu tłumaczenie powstaje kod wynikowy –
żeby go wykonać nie jest już potrzebny kompilator
2 Interpretery – interpretują i wykonują polecenia kodu źródłowego instrukcja po instrukcji: dlatego
za każdym razem, gdy chcemy sprawdzić, jak działa program, trzeba uruchamiać interpreter .
Przykładem języka kompilowanego jest język C++, natomiast interpretowanego – język Python.
Słowo kluczowe języka programowania oznacza określoną deklarację lub instrukcję i nie można go
przedefiniować. Słowa kluczowe w edytorach kodu są wyróżnione pogrubioną czcionką i/lub określonym
kolorem.
1 #include <iostream>
2
3 using namespace std;
4
5 int main()
6 {
7
8 }
Obok kodu źródłowego programu znajdują się numery, które są oznaczeniami kolejnych linii kodu. Ułatwiają
one omawianie znaczenia poszczególnych instrukcji. Programy pisane w języku C++ będziemy zapisywać i
uruchamiać w zintegrowanym środowisku programistycznym Code::Blocks .
UWAGA:
Aktualną wersję programu Code::Blocks pobierzesz ze strony : codebloks.org . Dostępne są na niej wersje
programu działające pod różnymi systemami operacyjnymi. Pracującym w systemie Windows zalecam pobranie
wersji oprogramowania zawierającej kompilator języki C++ (GCC/G++)
Aby w środowisku Code::Blocks utworzyć nowy, pusty plik, należy wybrać File → New → Empty file.
Program 1
Napisz program sprawdzający, czy liczba jest parzysta
Program ma za zadanie wczytać z klawiatury liczbę całkowitą, sprawdzić, czy jest parzysta i wypisać na ekranie
odpowiedni napis. Zakres danych ograniczymy ze względu na zakres reprezentowanych liczb całkowitych.
Specyfikacja:
Dane n – liczba całkowita, - 1 000 000 000 < n < 1 000 000 000.
Wynik : napis „Parzysta”, gdy n jest liczbą parzystą , napis „Nieparzysta”, gdy n jest liczbą
nieparzystą
jeśli n mod 2 = 0 to wypisz ”Parzysta”
Program C++ ignoruje tzw. białe znaki, czyli np. spacje, tabulacje. Dzięki temu możesz dostosować
czytelność kodu do swoich preferencji – ustawić takie wcięcia, jakie chcesz.
Kod bloku instrukcji programu (funkcji main) znajduje się pomiędzy nawiasami klamrowymi w liniach 7 – 13.
Deklaracja zmiennej w języku C++ składa się z nazwy zmiennej oraz typu danych, jakie może ona
przechowywać. Typ int oznacza liczby całkowite.
W linii 8 za pomocą instrukcji wejścia cin wczytujemy liczbę ze standardowego wejścia, czyli klawiatury.
Operator >> wskazuje, dokąd zostanie przesłana dana. W tym przypadku będzie zapamiętana w
zmiennej n.
W linii 9 badamy, czy reszta z dzielenia wartości zmiennej n przez 2 jest równa zero, czyli czy n jest liczbą
parzystą
Operator << wskazuje dane do przekazania na standardowe wyjście. W tym przypadku danymi są
teksty ”Parzysta” lub ”Nieparzysta”.
Ostatnia instrukcja programu (linia 13) kończy wykonywanie funkcji main (a w konsekwencji całego programu)
oraz informuje system operacyjny o poprawnym zakończeniu działania (kod 0).
Program 2
Napisz program dzielący liczbę na cyfry
Specyfikacja:
Wynik : kolejne cyfry liczby n, zaczynając od cyfry jedności (od prawej do lewej)
Kod programu wypisującego cyfry wczytanej liczby w pionie (każda cyfra w oddzielnym wierszu) może być
następujący:
Realizuje to instrukcja iteracji (pętla) while. Jej składania w języku C++ jest następująca:
Dopóki warunek przyjmuje wartość logiczną prawda, instrukcja w pętli jest powtarzana. Zwróć uwagę, że jeżeli
warunek pętli na początku przyjmie wartość logiczną fałsz, to instrukcja w pętli nie wykona się ani razu. W
powyższym programie tak się stanie, jeśli wczytamy liczbę ujemną lub zero. Wykonywana w pętli instrukcja
musi mieć też wpływ na warunek logiczny pętli, czyli zmieniać wartości, od których ten warunek zależy. W
przeciwnym przypadku warunek będzie miał cały czas wartość logiczną prawda i pętla będzie się wykonywała w
nieskończoność. W takich sytuacjach mówimy, że „program się pętli”.
W linii 12 zmienna n zmniejsza swoją wartość (jej dotychczasowa wartość jest dzielona całkowicie przez 10).
Znak = służy do przypisania wartości. Instrukcja przypisania wartości zmiennej w języku C++ ma postać:
w linii 11 wypisywana jest reszta z dzielenia wartości zmiennej n przez 10 oraz następuje przejście do
następnego wiersza ( wstawienie znacznika końca wiersza po drugim operatorze << , słowo kluczowe endl).
Zwróć uwagę na linie 10 i 13. Są tam nawiasy klamrowe wyznaczające blok instrukcji powtarzanych w pętli – są
one konieczne, jeśli w pętli (lub innej instrukcji, np. warunkowej if elese) chcemy wykonać więcej niż jedną
instrukcję. Blok instrukcji jest traktowany jak pojedyncza instrukcja.
Ćwiczenie 7
Napisz program dzielący liczbę na cyfry i przetestuj jego działanie.
Program 3
Napisz programy realizujące algorytmy podziału na równoliczne grupy
Utworzyliśmy wcześniej dwa algorytmy rozwiązywania tego problemu.
Specyfikacja:
W liniach 9 i 10 zastosowano instrukcję iteracji (pętlę) for. Stosuje się ją zwykle w sytuacjach, kiedy z góry
znamy liczbę powtórzeń.
instrukcja;
UWAGA:
instrukcja inicjująca;
instrukcja;
instrukcja modyfikująca;
Wartością początkową zmiennej d jest 2. Wykonywanie instrukcji pętli odbywa się, dopóki wartość zmiennej d
jest mniejsza lub równa n/2. Po każdym wykonaniu instrukcji pętli wartość zmiennej d jest powiększana o 1
(d++).
W pętli (linia 10) licznik dzielników ld jest powiększany o 1, gdy aktualna wartość d jest dzielnikiem n (reszta z
dzielenia jest równa 0).
Wypisanie na ekranie wyniku (linia 12), czyli wartości licznika dzielników , poprzedzone jest wypisaniem
komentarza (linia 11).
Poniżej znajduje się kod źródłowy drugiego algorytmu znajdującego liczbę dzielników właściwych danej liczby
większych od 1. Zwróć uwagę na modyfikację pętli for (linia 9).
Ćwiczenie 8
Zapisz, uruchom i przetestuj obie przedstawione w temacie wersje programów realizujących algorytm podziału
na równoliczne grupy.
ZAPAMIĘTAJ
Napisanie programu komputerowego stanowi tylko jeden z etapów rozwiazywania problemu algorytmicznego.
Najpierw należy precyzyjnie sformułować problem i podać jego specyfikację, następnie poszukać rozwiązania –
algorytmu. Dopiero potem można rozpocząć pisanie programu, pamiętając o testowaniu i ewentualnych
poprawkach.
PODSUMOWANIE
I. Wyróżniamy następujące etapy rozwiązywania problemów z wykorzystaniem komputera
określenie problemu (zadania)
podanie specyfikacji
sformułowanie rozwiązania – algorytmu
zaprogramowanie rozwiązania
testowanie rozwiązania
II. Specyfikacja zadania to określenia danych i wyniku oraz związku miedzy nimi
III. Algorytm to skończony ciąg precyzyjnie określonych instrukcji prowadzących do rozwiązania problemu
IV. Zapis algorytmu w języku programowania to kod źródłowy programu
V. Testowanie programu polega na wielokrotnym uruchamianiu go dla różnych danych (spełniających
warunki specyfikacji)
VI. Różne sposoby zapisu algorytmów to:
lista kroków
schemat blokowy
pseudokod
zapis w języku programowania
VII. Podstawowe instrukcje sterujące w językach programowania to instrukcja warunkowa (wykonywanie
instrukcji pod pewnym warunkiem) oraz instrukcja iteracji, czyli pętli (wielokrotne powtarzanie
instrukcji)
VIII. Translatory (które dzielimy na kompilatory i interpretery) to programy tłumaczące kod źródłowy
programu na język maszynowy
IX. Zintegrowane środowisko programistyczne (IDE) to program posiadający edytor do pisania kodu
źródłowego, translator oraz wiele funkcji ułatwiających uruchamiania programów.