Wstęp do programowania Dariusz Wardecki, wyk. I
Kontakt dward@fuw.edu.pl http://www.fuw.edu.pl/~dward/wdp ul. Hoża 69, pok. 114 tel. 22 55 32 181
Zasady zaliczenia Wykład (2h/tydzień) Egzamin pisemny Test wyboru 15 pkt. Ćwiczenia (2h/tydzień) 3 kolokwia po 15 pkt. 3 zadania po 5 pkt. Łącznie można zdobyć max 60 pkt.
Materiał na ćwiczenia Algorytmy. Podstawy programowania w C++ Funkcja main(), nagłówek i treść funkcji Obsługa wej/wyj Wyrażenia i zmienne Pętle Programowanie prostych obliczeń Liczby pseudolosowe Formatowanie wydruków i drukowanie wzorów Tablice i sortowanie liczb Wskaźniki i referencje Wej/wyj z wykorzystaniem plików Złożone typy danych i ich zastosowanie
Plan wykładu Kod źródłowy w C++ i kompilator g++ Algorytmy Złożoność obliczeniowa algorytmów Składnia języka C++, elementy składowe programów Proste typy danych Operatory i wyrażenia, konwerscje typów danych Pętle, instrukcja warunkowa i instrukcje sterujące w C++ Wskaźniki i tablice, operacje na wskaźnikach, Referencje Dynamiczne rezerwowanie pamięci i zwalnianie pamięci Tablice wskaźników i argumenty programu Złożone typy danych i ich zastosowania
Dlaczego warto uczyć się programowania komputerów Żeby zobaczyć na czym to polega Jeżeli mamy nietypowe zadanie, to czasem szybciej jest napisać własny program, niż szukać gotowego Czasami musimy być pewni, że program działa w ściśle określony sposób Może to być interesujące Stanowiska pracy związane z programowaniem bywają dobrze płatne
Na czym polega programowanie? Określenie problemu (co chcemy osiągnąć). Wybranie algorytmu, czyli metody poszukiwania rozwiązania (jak będziemy to robić). Tworzenie kodu źródłowego (ang. source code), stanowiącego reprezentację wybranego algorytmu. Kompilowanie kodu źródłowego, czyli tworzenie kodu wykonywalnego (ang. executable code) gotowego do wykonania. Sprawdzanie i testowanie (ang. debugging) programu. Jeżeli znajdziemy błąd, wracamy do etapu tworzenia kodu źródłowego (lub nawet do etapu wyboru algorytmu)
Trochę historii język C - początek lat siedemdziesiątych, Dennis Ritchie język C++ - koniec lat osimdziesiątych, Bjarne Stroustrup
Kod źródłowy i kompilator #include<iostream> using namespace std; int main() { cout << Hello World!!! << endl; return 0; } g++ -o nazwa nazwa.cc./nazwa Kod źródłowy w pliku nazwa.cc Kompilator Program
Logowanie na Primusa ssh Dom primus.okwf.fuw.edu.pl putty ssh login@tempac.fuw.edu.pl ssh login@primus.okwf.fuw.edu.pl Kompilator: g++ Edytor: nano, pico
Kod źródłowy Polecenie preprocesora #include<iostream> using namespace std; Przestrzeń nazw Funkcja main int main() { cout << Hello World!!! << endl; return 0; } Instrukcje
Algorytm SkoÒczony zbiór dobrze zdefiniowanych instrukcji przeznaczony do wykonania okreúlonego zadania, który przy ustalonym stanie poczπtkowym pozwala na uzyskanie odpowiedniego, rozpoznawalnego stanu koòcowego w skoòczonym czasie. W uproszczeniu Metoda poszukiwania (lub tworzenia) rozwiπzania zadanego problemu. Nie dla kaødego problemu istnieje skuteczny algorytm pozwalajπcy znaleüê rozwiπzanie. Problemy nieobliczalne (algorytm nie istnieje, np. busy beaver). Problemy, dla których algorytmy sπ zbyt z oøone (wykonywanie programu trwa oby zbyt d ugo).
Stan poczπtkowy dla algorytmu Dane wejúciowe (ang. input data). Stan koòcowy dla algorytmu Wynik (ang. result). Definicja poprawnoúci algorytmu Algorytm jest poprawny (ang. correct), gdy dla kaødych dopuszczalnych danych wejúciowych jednoczeúnie spe nione sπ dwa nastípujπce warunki: 1 Wynik jest otrzymywany w skoòczonej liczbie kroków problem zatrzymania (stopu). 2 Wynik stanowi rozwiπzanie problemu, dla którego algorytm zosta stworzony.
Przykłady: Oblicznie reszty z dzielenia (operacja modulo) Algorytm Euklidesa Sito Eratostenesa Dodawanie liczb w systemie dwójkowym Uniwersalny algorytm mnożenia (russian peasant algorithm) Przeszukiwanie binarne (ang. binary search) lub bisekcja (ang. bisection)
Obliczanie reszty z dzielenia niech n i m będą liczbami naturalnymi, n > m 1.Niech k = n 2.Jeśli k < m, to k jest resztą z dzielenia, k = n%m 3.Niech k = k - m 4.Przejdź do kroku 2
Algorytm Euklidesa Algorytmy Niech n i m będą liczbami nauralnymi, n > m. Wyznaczamy największy wspólny dzielnik n i m, czyli NWD(n, m) Obserwacja Jeśli r jest resztą z dzielenia n przez m, to n = km + r (dla pewnego całkowitego k), więc NWD(n, m) = NWD(m, r)
Algorytm Euklidesa Algorytmy Niech a, b i r będą miejscami do przechowywania wyników 1.Niech a = n i b = m. 2.Niech r = a%b (resztę z dzielenia a/b zapisujemy w r). 3.Jeśli r = 0, to NWD(n, m) = b. 4.Niech a = b i b = r. 5.Przejdź do kroku 2.
Sito Eratostenesa - chcemy ustalić, które z liczb naturalnych nie większych od zadanego N są liczbami pierwszymi. A = {2,3,, N}, k i m - miejsca do przechowywania pośrednich wyników 1) Niech k = 2 2) Jeśli k² > N, zbiór A zawiera tylko liczby pierwsze 3) Usuwamy z A wszystkie wielokrotności k, począwszy od k² 4) W m zapisz najmniejszą liczbę ze zbioru A większą od k. 5) Niech k = m. 6) Przejdź do kroku 2).
Dodawanie liczb w systemie dwójkowym a b c 0 0 0 1 0 1 0 1 1 1 1 10 1 1 0 1 1 0 1 0 1 1 1 0 1 1 0 1 1
Mamy dwie liczby N-cyfrowe w zapisie dwójkowym: a = N 1 X a j 2 j b = N 1 X b j 2 j j=0 j=0 gdzie a j,b j 2 {0, 1} są cyframi. Chcemy wyznaczyć współczynniki (cyfry) w j 2 {0, 1} w rozwinięciu ich sumy. a + b = w = NX j=0 w j 2 j dla danych oraz. a j b j
Dodawanie liczb w systemie dwójkowym Wprowadzamy funkcje: PAR(x, y, z) =(x + y + z) %2 MAJ(x, y, z) =(x + y + z)/2 gdzie x, y, z œ {0, 1}, aznak/ oznacza dzielenie z pominiíciem reszty. Definiujemy ciπg c 0 = 0, c j = MAJ(a j 1, b j 1, c j 1 ) dla j = 1, 2,...,N. Wtedy c j jest przeniesieniem (ang. carry) z pozycji (j 1) na pozycjí j podczas dodawania, wiíc mamyw N = c N oraz w j = PAR(a j, b j, c j ) dla j = 0, 1,...,N 1.
Algorytm dodawania Niech C bídzie miejscem s uøπcym do przechowywania poúrednich wartoúci, natomiast k bídzie licznikiem. 1 Niech C = 0, k = 0. 2 Niech w k = PAR(a k, b k, C). 3 Niech C = MAJ(a k, b k, C). 4 Niech k = k + 1. 5 Jeúli k < N, przejdü do kroku 2. 6 Niech w N = C. 7 Ciπg cyfrw 0, w 1, w 2,...,w N stanowi wynik.
Uniwersalny algorytm mnożenia Russian peasant algorithm Obliczamy wynik mnoøenia dwóch nieujemnych liczb ca kowitych a i b: 1 Niech a 0 = a, b 0 = b i k = 0. 2 Niech k = k + 1. 3 Niech a k = a k 1 /2 (dzielenie bez reszty) i b k = 2b k 1. 4 Jeúli a k > 1, to przejdü do kroku 2. 5 Wynik mnoøenia jest sumπ wszystkich b k (k = 0, 1, 2,...), dla których odpowiadajπce im a k sπ nieparzyste.
Uniwersalny algorytm mnożenia Obliczamy iloczyn 156 18 1 Wyznaczamy ciπgi a k i b k : k a k b k 0 156 18 1 78 36 2 39 72 3 19 144 4 9 288 5 4 576 6 2 1152 7 1 2304 2 156 18 = 2304 + 288 + 144 + 72 = 2808
Uniwersalny algorytm mnożenia Obliczamy iloczyn 156 18 1 Moøna sumowaê na bieøπco k a k b k s k 0 156 18 0 1 78 36 0 2 39 72 72 3 19 144 216 4 9 288 504 5 4 576 504 6 2 1152 504 7 1 2304 2808 2 156 18 = s 7 = 2808
Uniwersalny algorytm mnożenia Obliczamy iloczyn dwóch nieujemnych liczb ca kowitych a i b Niech A, B i S bídπ miejscami s uøπcymi do przechowywania poúrednich wyników. 1 Niech A = a, B = b i S = 0. 2 Jeúli A % 2 = 1 (wartoúê w A jest nieparzysta), to S = S + B. 3 Jeúli A = 1, przejdü do kroku 6. 4 Niech A = A/2 (dzielenie bez reszty) i B = 2B. 5 Przejdü do kroku 2. 6 Wynik mnoøenia jest zapisany w S.
Przeszukiwanie binarne (bisekcja) Poszukiwanie elementu r w skoòczonym i uporzπdkowanym zbiorze B 1 Niech B 0 = B i k = 0. 2 Jeúli wszystkie elementy zbioru B k sπ jednakowe lub B k jest zbiorem pustym, przejdü do kroku 6. 3 Niech m k oznacza medianí zbioru B k. 4 Jeúli r m k,toniechb k+1 = {b œ B k : b m k },awprzeciwnym wypadku niech B k+1 = {b œ B k : b > m k }. 5 Niech k = k + 1 i przejdü do kroku 2. 6 Jeúli r œ B k,tor œ B.
Przeszukiwanie binarne (bisekcja) - przykład Weümy B = {3, 7, 21, 48, 56, 122, 141, 218, 225, 248} i r = 225 k B k m k 0 {3, 7, 21, 48, 56, 122, 141, 218, 225, 248} 56 1 {122, 141, 218, 225, 248} 218 2 {225, 248} 225 3 {225} 225