Najważniejsze aspekty w metodyce nauczania programowania, czyli w jaki sposób uczyć programowania (w szkole) Krzysztof Diks, II UW Podsumowanie wyników z matury 2013 • Poziom podstawowy: Dla zdających najtrudniejsze okazało się zadanie 4. z zakresu algorytmiki i programowania. • Poziom rozszerzony: Trudność maturzystom sprawiły zadania 6.b i 6.c z zakresu algorytmiki i programowania. 2 3 2005 4 2005 5 2007 6 Przyczyna Nie wyartykułowano, co ma być celem początkowej fazy nauki programowania. Celami wstępnej fazy nauki programowania nie powinny być: •szczegółowe poznanie (składni) wybranego języka programowania •kształcenie umiejętności tworzenia (często technicznych) aplikacji •szczegółowe poznawanie środowisk wspierających pracę programisty 7 Przyczyna Nie zdefiniowano co to jest programowanie dla początkujących adeptów informatyki. KD, GJ: Programowanie, to formalny sposób zapisywania algorytmów, a co za tym idzie nie należy w procesie nauczania rozdzielać algorytmiki i programowania. 8 Wady istniejących podręczników do uczenia elementów programowania (w liceach) • rozdzielenie nauki programowania od układania algorytmów • duży nacisk na nauczanie składni i szczegółów technicznych języka programowania, zamiast na uczenie rozumienia podstawowych konstrukcji programistycznych (zapisywania algorytmów) • brak kształcenia umiejętności projektowania poprawnych algorytmów • dominujące używanie schematów blokowych (listy kroków) do zapisywania algorytmów • nieciekawe, techniczne przykłady • dominacja odtwórczych zadań • wprowadzanie „klasycznych” algorytmów bez uzasadniania dlaczego zaliczamy je do klasyki (ze względu na wagę rozwiązywanego problemu? ze względu na wagę i ogólność użytych w nich metod?) 9 Rozdzielenie nauki programowania od układania algorytmów …W rozdziale II (Algorytmika i programowanie - problemy zaawansowane) poszerzamy wiadomości dotyczące wprowadzania danych i wyprowadzania wyników, m.in. losowanie danych. Systematyzujemy wiedzę uczniów dotyczącą typów danych w języku Turbo Pascal. Uczniowie poznają zasady przetwarzania rekordów i plików, w tym plików tekstowych. Zapoznają się z cechami programowania obiektowego na przykładzie języka Object Pascal. Dowiadują się, na czym polega programowanie zdarzeniowe - tworzą interfejs użytkownika w systemie Delphi. Poznają elementy analizy algorytmów. Analizują wybrane algorytmy sortowania oraz algorytmy wykonujące operacje na liczbach naturalnych. Poznają reprezentację danych numerycznych w komputerze oraz wybrane algorytmy numeryczne. … 10 Duży nacisk na nauczanie składni i szczegółów technicznych języka programowania, zamiast na uczenie rozumienia podstawowych konstrukcji programistycznych (zapisywania algorytmów) …Kolejną pętlą w C++ jest pętla while. Pętla ta wykonuje się kolejny raz, gdy wyrażenie jest prawdziwe (czyli ma wartość różną od zera). Składnia pętli while while (wyrażenie) instrukcja; gdzie: wyrażenie instrukcja -wyrażenie przyjmujące wartość logiczną „prawda” albo „fałsz” - instrukcja wykonywana w pętli Napiszmy prosty program wyświetlający na ekranie znaki podane z klawiatury do momentu, aż podamy znak „k”. 11 #include <iostream> #include <cstdio> using namespace std; int main() { char z; cout << ˝podaj znak ˝; cin >> z; while (z != ‘k’) { cout << ˝ Podaj kolejny znak ˝; cin >> z; } cout << ˝ Podales ˝ << z << ˝ wiec koncze˝; cin.ignore(); getchar(); return 0; } 12 Brak kształcenia umiejętności projektowania poprawnych algorytmów …Metodami, jakie się w takich przypadkach stosuje zajmiemy się w przyszłym roku. Na co dzień muszą wystarczyć poniższe zasady: •staraj się wykorzystywać sprawdzone pewne algorytmy; mogą to być procedury, ale też fragmenty poprzednio wykorzystywanych algorytmów; gromadź takie stałe fragmenty gry w swojej podręcznej biblioteczce; •na etapie tworzenia algorytmu możesz być wizjonerem, artystą, na etapie sprawdzania, czy algorytm działa zgodnie z Twoimi zamierzeniami, powinieneś być skrupulatnym, podejrzliwym kontrolerem, który sprawdza każdy szczegół, nie wierzy nikomu, nawet sobie; •ćwicz – pisz programy, podpatruj, jak inni to robią, stale szukaj nowych, lepszych rozwiązań… 13 Dominujące używanie schematów blokowych (listy kroków) do zapisywania algorytmów Problem algorytmiczny: Badanie, czy podana liczba jest pierwsza Dane wejściowe: liczba naturalna n > 1 – badana liczba Dane wyjściowe: napis „liczba pierwsza”, gdy n jest liczbą pierwszą, lub napis „liczba złożona”, gdy n jest liczbą złożoną Zmienne pomocnicze: liczba naturalna i – potencjalny dzielnik; i > 1 1. 2. 3. 4. 5. 6. Wczytaj n. Zmiennej pomocniczej i przypisz wartość 2. Jeśli kwadrat liczby i jest większy od liczby n, to wypisz „liczba pierwsza” i zakończ. Jeśli reszta z dzielenia n przez i wynosi 0, wypisz ‘liczba złożona” i zakończ. Zwiększ o 1 wartość zmiennej pomocniczej i. Przejdź do kroku 3. 14 Nieciekawe, techniczne przykłady Przykład użycia instrukcji iteracyjnej while uses CRT; var powtórz:boolean; procedure sprawdz(var powtorz: boolean); var c:char; begin write(‘Czy powtórzyć (nacisnij t/T jeśli TAK)? ‘); c := ReadKey; Writeln(c); powtorz := UpCase(c)=‘T’; writeln end; begin powtorz := True; while powtorz do begin czytajDane(m,n); wypisz(m,n); sprawdz(powtorz); end end. 15 Dominacja odtwórczych zadań Napisz program realizujący algorytm z przykładu 5. Posłuż się danymi generowanymi losowo. Zanotuj, ile operacji każdorazowo wykonał program (liczba operacji będzie równa numerowi znalezionego elementu lub n, gdy element nie zostanie znaleziony). Oblicz średnią liczbę operacji dla wszystkich wykonań programu. 16 Wprowadzanie „klasycznych” algorytmów bez uzasadniania dlaczego zaliczamy je do klasyki (ze względu na wagę rozwiązywanego problemu? ze względu na wagę i ogólność użytych w nich metod?) Z podstawy programowej: algorytmy wyszukiwania i porządkowania (sortowania), np.: – jednoczesne znajdowanie największego i najmniejszego elementu w zbiorze: algorytm naiwny i optymalny, – algorytmy sortowania ciągu liczb: bąbelkowy, przez wybór, przez wstawianie liniowe lub binarne, przez scalanie, szybki, kubełkowy. 17 Wstęp do programowania w ujęciu algorytmicznym - podstawy Sylabus: • algorytm (specyfikacja, dziedzina algorytmiczna, zapisywanie algorytmów) • kodowanie algorytmów (instrukcje: warunkowa i iteracji) •funkcja • zmienne • projektowanie iteracji, poprawność algorytmu • tablice • złożoność obliczeniowa algorytmu 18 W jaki sposób układamy i zapisujemy algorytmy - przykłady Zadanie 1 – pierwiastek dyskretny Dane: nieujemna liczba całkowita n Wyniki: nieujemna liczba całkowita n p taka, że p2 <= n < (p+1)2 Dozwolone operacje: dodawanie i odejmowanie liczb całkowitych porównywanie liczb całkowitych Uwaga: w języku matematyki chcemy umieć obliczać wartość funkcji pierwiastekDyskretny(n) = [sqrt(n)]. 19 Algorytm w języku naturalnym: weź 0 na kandydata dopóki następnik kandydata spełnia nierówność pierwiastka: niech ten następnik będzie nowym kandydatem aktualny kandydat to poszukiwany pierwiastek dyskretny Python: def pierwiastekDyskretny(n): k=0 while (k+1)*(k+1) <= n: k=k+1 return k 20 C++: int pierwiastekDyskretny(int n) { int k = 0; while ( (k+1)*(k+1) <= n) ) { k = k + 1; } return k } 21 Przyśpieszanie algorytmu – projektowanie pętli od środka Spostrzeżenie 1: pierwiastek dyskretny p z n leży w przedziale [0..n] Spostrzeżenie 2: załóżmy, że p leży w przedziale [le..pr] i niech k będzie liczbą całkowitą z tego przedziału, wówczas jeśli (k+1)*(k+1) <= n, to p leży w przedziale [k+1..pr] jeśli k*k > n, to p leży w przedziale [le..k-1] 22 Projektowanie wnętrza pętli Asercja: le <= p <=pr, co oznacza, że le*le <= n < (pr+1)*(pr+1) k = (le+pr)/2 if (k+1)*(k+1) <= n: le = k+1 if k*k > n: pr = k - 1 23 Python: def pierwiastekDyskretny(n): assert n >= 0 le = 0 pr = n while True: assert (le*le <= n) AND ((pr+1)*(pr+1) > n) k = (le + pr) / 2 if (k+1)*(k+1) <= n: le = k+1 continue if k*k > n: pr = k-1 continue assert (k<= n) AND ((k+1)*(k+1) > n) break return k 24 int pierwiastekDyskretny(int n){ int le, pr, k; assert (n >= 0); le = 0; pr = n; while (True){ assert ((le*le <= n) && ((pr+1)*(pr+1) > n)); k = (le + pr) / 2; if ((k+1)*(k+1) <= n){ le = k+1; continue; } if (k*k > n){ pr = k-1; continue; } assert ((k<= n) && ((k+1)*(k+1) > n)); break; } return k; } 25