Narzędzie pomocnicze przedmiotu Podstawy Informatyki - złożoność obliczeniowa Piotr Jeruszka 1 25 listopada 2013 1 Instytut Informatyki Teoretycznej i Stosowanej Politechnika Częstochowska pjeruszka@icis.pcz.pl 1 Wstęp Przedstawione narzędzie jest prostym programem (właściwie - kodem źródłowym), mającym pomóc studentom przedmiotu Podstawy Informatyki w zrozumieniu i analizie złożoności obliczeniowej. Głównym zadaniem przedstawionego kodu jest wyliczenie liczby porównań w warunku pętli zewnętrznej (L z ), wewnętrznej (L w ) oraz sumarycznej liczby porównań w całym programie (L c ). W przypadku, gdy użytkownik wyliczył odpowiednie wzory (na L z, L w i L c ) możliwe jest sprawdzenie ich poprawności. Z punktu widzenia użytkownika program składa się z trzech części: części deklaracyjnej, w której użytkownik podaje liczbę N. Podawane jest również (w formie zmiennej logicznej) opcjonalne wyświetlenie wartości zmiennych przy każdym porównaniu (zmienna datki): /* poniżej podaj n */ n = 6; /* jeżeli datki = true, to zostaną wypisane kolejne kroki */ datki=true; kodu źródłowego, który jest właściwym obiektem analizy. W tym prostym kumencie analizowane będzie zadanie 1.1 z 5 listy zadań. Należy samodzielnie przepisać algorytm podany w formie pseukodu/kodu źródłowego na kod źródłowy w języku Java/C++ 1. części wypisującej statystyki (w formie wywołania funkcji wypiszstatsydlan). Tylko te trzy części powinny być edytowane przez użytkownika. 1 Na obecnym etapie poznawania języków programowania składnia Javy i C++ jest identyczna. 1
2 Wymagania Program został napisany w języku Java. Do kompilacji i uruchomienia programu wymagane są: kompilator javac; na Winwsie stępny w pakiecie JDK (stępny na stronie Oracle), na Linuksach w formie pakietu (Ubuntu: default-jdk). maszyna wirtualna Javy, zintegrowana z wymienionymi pakietami. 3 Uruchomienie Aby wygodnie pracować z starczonym kodem, należy wykonać poniższe kroki. 1. Otworzyć plik Main.java w ulubionym edytorze tekstu bądź wybranym śrowisku programistycznym. 2. Ustawić żądaną wartość n - wystarczy po prostu zmienić liczbę, która stoi po prawej stronie operatora =. 3. Można zmienić wartość datki na true - spowoduje to wypisanie przy każdym porównaniu aktualnych wartości zmiennych i, j (w przypadku pętli wewnętrznej) i n. 4. W wyznaczonym miejscu: /* Poniżej wpisz kod źródłowy */... /* tutaj zakończ wpisywanie kodu źródłowego */ zamiast kropek należy zapisać kod źródłowy. 5. Przed pętlą zewnętrzną należy zapisać literkę z, przed pętlą wewnętrzną należy pisać literkę w. Z technicznego punktu widzenia jest to wywołanie odpowiednio (statycznych) funkcji z i w, które inkrementują odpowiednie liczniki. 6. Gotowy program należy skompilować, używając programu javac: $ javac Main.java 7. Po poprawnej kompilacji program należy uruchomić w konsoli: $ java Main W przypadku systemów z powłoką bash kompilację i uruchomienie można zastąpić uruchomieniem starczonego skryptu o.sh: $./o.sh Poprawne uruchomienie spowoduje wyświetlenie odpowiednich wartości, przykławo: 2
N = 6 Lw = 36 Lz = 7 Lc = 43 a w przypadku ustawienia zmiennej datki na true - wartości zmiennych przy każdym porównaniu, przykławo: Z i = 0 N = 6 ; W i = 0 j = 1 N = 6 ; W i = 0 j = 2 N = 6 ; W i = 0 j = 3 N = 6 ; W i = 0 j = 4 N = 6 ; W i = 0 j = 5 N = 6 ; W i = 0 j = 6 N = 6 ; Z i = 1 N = 6 ; (...) W i = 5 j = 5 N = 6 ; W i = 5 j = 6 N = 6 ; Z i = 6 N = 6 ; N = 6 Lw = 36 Lz = 7 Lc = 43 (Z oznacza porównanie w pętli zewnętrznej, W - porównanie w pętli wewnętrznej). 4 Przykład Zostanie przedstawione przykławe użycie programu sprawdzenia wyliczonych wartości dla zadania 1.1 (5 lista zadań). Zadanie to ma następującą treść: Na podstawie fragmentu pseukodu podaj liczbę porównań i oszacuj złożoność w sensie notacji O( ) 1. póki (i<n) wykonuj: wykonuj: póki (j<n); Wyliczamy (co będzie przedstawione na ćwiczeniach) wzory na odpowiednie wartości: L z = N + 1; L w = N 2 ; L c = N 2 + N + 1 (1) co pozwala nam podać złożoność obliczeniową: O(N 2 ). Dla pewności zostanie to sprawdzone dla N = 6. 1. Należy otworzyć plik Main.java i ustawić n=6. Chcemy również, by wyświetlane było każde porównanie: 3
/* poniżej podaj n */ n = 6; /* jeżeli datki = true, to zostaną wypisane kolejne kroki */ datki=true; 2. Wpisujemy kod źródłowy, który jest tożsamy z pseukodem. Języki Java/C++ oferują m.in. pętle: while odpowiednik pętli póki (warunek) wykonuj:...while odpowiednik pętli wykonuj:... póki (warunek) Dla osób, które nie czują się zbyt pewnie w pisaniu programów w C++ proponowany jest następujący sposób zapisu kodu źródłowego: należy (w miejsce, gdzie powinien być kod źródłowy) przepisać treść zadania, pamiętając o wcięciach: póki (i<n) wykonuj: wykonuj: póki (j<n); pętla wykonuj:... póki (warunek) zostanie zapisana w ten sposób: póki (i<n) wykonuj: while (j<n); pętla póki (warunek) wykonuj: zostanie zapisana w ten sposób: while (i<n) while (j<n); 4
3. Kolejnym krokiem jest pisanie odpowiednich literek przed warunkami w pętlach: while z(i<n) //pętla zewnętrzna while w(j<n); //pętla wewnętrzna (znak // oznacza początek komentarza, nie jest on wymagany w kodzie źródłowym) 4. Ponieważ warunki muszą być zapisane w nawiasach - należy zawrzeć to, co jest podane przy słowie while w datkową parę nawiasów: while (z(i<n)) //pętla zewnętrzna while (w(j<n)); //pętla wewnętrzna Kod analizowanego programu, łącznie z ustawionymi przez użytkownika wartościami powinien wyglądać pobnie poniższego: public static void main(string[] args) /* poniżej podaj n */ n = 6; /* jeżeli datki = true, to zostaną wypisane kolejne kroki */ datki=true; /* Poniższego kodu nie zmieniaj */ (...) */ Poniżej wpisz kod źródłowy */ 5
while (i<n) while (j<n); /* tutaj zakończ wpisywanie kodu źródłowego */ wypiszstatsydla(n); Skompilowanie i uruchomienie spowoduje wyświetlenie na wyjściu programu następującego ciągu znaków: Z i = 0 N = 6 ; W i = 0 j = 1 N = 6 ; W i = 0 j = 2 N = 6 ; W i = 0 j = 3 N = 6 ; W i = 0 j = 4 N = 6 ; W i = 0 j = 5 N = 6 ; W i = 0 j = 6 N = 6 ; Z i = 1 N = 6 ; W i = 1 j = 1 N = 6 ; W i = 1 j = 2 N = 6 ; W i = 1 j = 3 N = 6 ; W i = 1 j = 4 N = 6 ; W i = 1 j = 5 N = 6 ; W i = 1 j = 6 N = 6 ; Z i = 2 N = 6 ; W i = 2 j = 1 N = 6 ; W i = 2 j = 2 N = 6 ; W i = 2 j = 3 N = 6 ; W i = 2 j = 4 N = 6 ; W i = 2 j = 5 N = 6 ; W i = 2 j = 6 N = 6 ; Z i = 3 N = 6 ; W i = 3 j = 1 N = 6 ; W i = 3 j = 2 N = 6 ; W i = 3 j = 3 N = 6 ; W i = 3 j = 4 N = 6 ; W i = 3 j = 5 N = 6 ; W i = 3 j = 6 N = 6 ; Z i = 4 N = 6 ; W i = 4 j = 1 N = 6 ; W i = 4 j = 2 N = 6 ; W i = 4 j = 3 N = 6 ; 6
W i = 4 j = 4 N = 6 ; W i = 4 j = 5 N = 6 ; W i = 4 j = 6 N = 6 ; Z i = 5 N = 6 ; W i = 5 j = 1 N = 6 ; W i = 5 j = 2 N = 6 ; W i = 5 j = 3 N = 6 ; W i = 5 j = 4 N = 6 ; W i = 5 j = 5 N = 6 ; W i = 5 j = 6 N = 6 ; Z i = 6 N = 6 ; N = 6 Lw = 36 Lz = 7 Lc = 43 Jeżeli sekwencji wzorów (1) zostanie podstawione N = 6, to wartości będą następujące: L z = 7; L w = 36; L c = 43; (2) czyli kładnie to, co zostało obliczone w programie. 5 Zaawansowana analiza porównań Program oferuje kładną prezentację porównań. W tym celu przygotowano funkcje (statyczne): Funkcja wieksze(a, b) mniejsze(a, b) wieksze_rowne(a, b) mniejsze_rowne(a, b) rowne(a, b) rozne(a, b) Warunek zastępowany a > b a < b a >= b a <= b a == b a!= b które przy zmiennej datki==true spowodują wyświetlenie datkowych informacji. Należy ich użyć zamiast wbuwanych warunków (funkcji) porównujących. Dla przykładu zostanie użyty utworzony kod zadania 1.1: while (z(i<n)) //pętla zewnętrzna while (w(j<n)); //pętla wewnętrzna 7
W przypadku pierwszej pętli while (z(i<n)) //pętla zewnętrzna warunek można zastąpić wywołaniem funkcji mniejsze: while (z(mniejsze(i,n)) //pętla zewnętrzna Pobne działanie można wykonać w pętli wewnętrznej: while (w(mniejsze(j,n)); //pętla wewnętrzna Analizowany kod źródłowy powinien być pobny poniższego: while (z(mniejsze(i,n))) while (w(mniejsze(j,n))); Ze względu na sposób działania funkcji orzekających zmodyfikowany kod jest równoznaczny z przeanalizowanym programem z poprzedniego rozdziału. Przy ustawieniu zmiennej datki=true wyjście programu powinno być pobne poniższego: Z i = 0 N = 6 ; porównanie 0 < 6, wynik: PRAWDA W i = 0 j = 1 N = 6 ; porównanie 1 < 6, wynik: PRAWDA W i = 0 j = 2 N = 6 ; porównanie 2 < 6, wynik: PRAWDA W i = 0 j = 3 N = 6 ; porównanie 3 < 6, wynik: PRAWDA W i = 0 j = 4 N = 6 ; porównanie 4 < 6, wynik: PRAWDA W i = 0 j = 5 N = 6 ; porównanie 5 < 6, wynik: PRAWDA W i = 0 j = 6 N = 6 ; porównanie 6 < 6, wynik: FAŁSZ Z i = 1 N = 6 ; porównanie 1 < 6, wynik: PRAWDA (...) W i = 5 j = 1 N = 6 ; porównanie 1 < 6, wynik: PRAWDA W i = 5 j = 2 N = 6 ; porównanie 2 < 6, wynik: PRAWDA W i = 5 j = 3 N = 6 ; porównanie 3 < 6, wynik: PRAWDA W i = 5 j = 4 N = 6 ; porównanie 4 < 6, wynik: PRAWDA W i = 5 j = 5 N = 6 ; porównanie 5 < 6, wynik: PRAWDA W i = 5 j = 6 N = 6 ; porównanie 6 < 6, wynik: FAŁSZ Z i = 6 N = 6 ; porównanie 6 < 6, wynik: FAŁSZ N = 6 Lw = 36 Lz = 7 Lc = 43 Jak można zauważyć - datkowym ułatwieniem dla użytkownika jest wyświetlenie datkowych informacji o aktualnie porównywanych w warunku pętli wartościach (porównanie 0 < 6) oraz wyniku tego porównania (wynik: PRAWDA). 8
Dodatek: uruchomienie programu w systemie Winws Najłatwiejszym rozwiązaniem jest instalacja pakietu JDK ze śrowiskiem programistycznym NetBeans. 1. Na stronie Oracle wyszukujemy pakiet nazwany JDK 7uXX with NetBeans. W chwili pisania tego kumentu żądany pakiet jest stępny na tej stronie. Ściągamy wersję stosowaną naszego systemu operacyjnego. 2. Instalujemy JDK wraz ze śrowiskiem NetBeans. 3. Uruchamiamy NetBeans, następnie z menu File wybieramy kolejno: New Project, Java, Java Application, Next. W polu Create Main Class wpisujemy Main i wciskamy Finish. 4. W nowo otwartym pliku Main.java wklejamy zawartość pliku o tej samej nazwie. 5. Uruchomienie polega na kliknięciu ikony zielonej strzałki w górnym menu śrowiska. 9