Programowanie – czerwiec 2006 Wersja A
Transkrypt
Programowanie – czerwiec 2006 Wersja A
Programowanie – czerwiec 2006 Wersja A Za cały egzamin będzie można dostać 100 punktów (nie licząc punktów bonusowych). Progi są następujące: 34 punkty daje ocenę dostateczną, 47 dostateczną z plusem, 60 dobrą, 73 dobrą z plusem, 86 bardzo dobrą. W jednym zadaniu pojawia się sformułowanie inny niż Haskell język programowania. Oznacza ono jeden z języków: Pascal, C, C++, Python, SML lub Prolog. We wszystkich zadaniach programistycznych liczy się również elegancja rozwiązania. Zadanie 1. (13p) Gramatyka G1 nad alfabetem {a, b}, określona jest przez przez zbiór produkcji P 1 P1 = {S → aSa, S → bSb, S → ε, , S → a, S → b} Opisz krótko zbiór L(G1 ) (2p) Gramatyka G2 nad alfabetem {a, b}, określona jest przez przez zbiór produkcji P 2 P2 = {S → aSb, S → bSa S → ε, S → SS} Opisz krótko zbiór L(G2 ) (2p) Niech X = L(G1 ) ∩ L(G2 ). Przez w R będziemy rozumieli słowo w przeczytane wspak, t.zn. przykładowo: abbabR = babba. Zdefiniuj warunek Φ(w), tak żeby X = {ww R | Φ(w)} (3p). Rozpatrując osobno obie inkluzje uzasadnij że Twoja definicja jest poprawna. (6p) Zadanie 2. (15p) Zamień poniższe programy na ich odpowiedniki, w których nie ma instrukcji goto, a jedynymi strukturami sterującymi są pętle while, do-while i instrukcja if. Możesz wprowadzać nowe zmienne, przypisywać im wartości i sprawdzać je. Występujące w programach warunki nie wywołują efektów ubocznych. a) (5p) do { if (b) { C1; if (b2) continue; C2; } if (b3) break; C4; while (b4) b) (5p) if (b1) goto L1; switch (c) { case 1: C1; case 2: C2; break; case 3: C3; } L1: C4; c) (5p) while (b) { C1; L2: C2; } if (b2) goto L2; Zadanie 3. (15p) Poniższe fragmenty programów w języku C nie robią tego, co mają robić. Dla każdego z nich powiedz, gdzie jest problem i napisz program poprawnie (zwróć również uwagę na styl): a) Program wypisuje, tę liczbę, która w posortowanej tablicy występuje w największej liczbie egzamplarzy. Jeżeli takich liczb jest więcej, powinien wypisać największą. // ... Ile = 0; Max = 0; for (i=0; i< N; i++) { if (T[i] == T[i+1]) { Ile ++; if (Ile > Max) { Max = Ile; Nr = i; } } } printf("Najczęściej występowała liczba %d\n",Nr); b) Funkcja zwraca „podwojone” słowo, które jest jej argumentem. Przykładowo dla "bla" wynikiem powino być "blabla" char* podwoj(char *s) { int len = strlen(s); for (int i=0; i<=len; i++) s[i+len] = s[i++]; return s; } c) Funkcja smartcopy(char *s,char *t) kopiuje zawartość napisu *s pod adres t. Zakładamy, że pod adresem t jest wystarczająco dużo miejsca, ale za to funkcja powinna działać poprawnie również wówczas, gdy napisy s oraz t nachodzą na siebie w pamięci. void smartcpy(char *s, char *t) { int delta=0; int len = strlen(s); char *start; if (s<t) { delta = +1; start = p; } if (s>t) { delta = -1; 2 start = p + len; } for (i=0; i<len; i++) t[i] = s[start+delta*i]; } Zadanie 4. (36p) W zadaniu typ preferowanym językiem jest Haskell. Można jednak używać innego języka, (opisując jak realizuje się listy i pary), ale wówczas traci się premie za użycie wymienionych w zadaniu haskellowych konstrukcji lub funkcji. Będziemy rozważać programy sortujące tablicę N elementową L = [x 1 , . . . , xN ] (reprezentowaną jako listę), które składają się z instrukcji swap(K 1 , K2 ), gdzie 1 ≤ K1 < K2 ≤ N . Instrukcja swap nic nie robi, jeżeli xK1 < xK2 , w przeciwnym przypadku zamienia ze sobą miejscami elementy o indeksach K1 , K2 . Sieć sortująca jest ciągiem instrukcji swap. Instrukcje swap będziemy reprezentować jako pary liczb całkowitych. Dla sieci sortujących prawdziwy jest następujący fakt: sieć, która prawidłowo sortuje wszystkie ciągi zero-jedynkowe, prawidłowo sortuje wszystkie tablice wypełnione dowolnymi liczbami (nie musisz tego dowodzić, nazywa się to zasadą zerojedynkową). a) Napisz funkcję nth :: Integer -> [a] -> a, zwracającą n-ty element listy. (3p) b) Napisz funkcję doSwap :: Ord a => (Integer,Integer) -> [a] -> [a], która „wykonuje” jedną instrukcję swap (to znaczy argumentem jest instrukcja swap oraz lista wejściowa, a wynikiem jej jest lista otrzymana z listy wejściowej po wykonaniu jednego swapa.(5p) c) Napisz funkcję seq01 :: Integer -> [ [Integer] ], która dla danego N zwraca listę wszystkich ciągów zerojedynkowych o długości N . Kolejność nie ma znaczenia (premia do 2p za skorzystanie z mechanizmu list comprehension). (4+2p) d) Napisz funkcję sorted:: wana. (3p) Ord a => [a] -> Bool, sprawdzającą czy lista jest posorto- e) Oto dwie definicje funkcji haskellowych: mf [] x = x mf (f:fs) x = mf fs (f x) funkcje Pairs = map (\p -> doSwap p) Pairs Podaj ich typy i opisz krótko działanie. (8p) f) Napisz funkcje doAllSwaps :: Ord a => [(Integer,Integer)] -> [a] -> [a], która „wykonuje” po kolei wszystkie instrukcje swap zawarte w pierwszym argumencie. Premia 3p za wykorzystanie obu definicji z poprzedniego podpunktu (3+3) g) Napisz funkcję goodSorter :: Integer -> [(Integer,Integer)] -> Bool, która korzystając z zasady zerojedynkowej sprawdza, czy sieć sortująca dana jako drugi argument poprawnie sortuje wszystkie tablice o wielkości danej jako pierwszy argument. (5p) Zadanie 5. (12p) W zadaniu tym należy używać Prologa. a) Napisz predykat append(A,B,C), prawdziwy, gdy lista C jest złączeniem list A i B. (3p) 3 b) Wyrażenie regularne bez gwiazdki nad alfabetem {a, b} można kodować za pomocą termu prologowego w naturalny sposób używając znaku mnożenia jako oznaczenia konkatenacji oraz atomów a, b, epsilon oraz zero dla oznaczenia a, b, ε, ∅. Przykładowo wyrażeniu a(ab+ba+ε) odpowiada term a*(a*b+b*a+epsilon). Napisz predykat pasuje(Wyrazenie,Lista), sprawdzający, czy słowo pamiętane jako lista liter (Lista) należy do języka generowanego przez Wyrażenie (9p). Zadanie 6. (12p) Czy poniższe zdania są prawdziwe? Proszę o odpowiedź na każde z pytań, przy czym odpowiedź należy wybrać ze zbioru: T,N,?. Odpowiedź ? warta jest zawsze 0 punktów, odpowiedi T oraz N są warte -2 lub 2, w zależności od tego, czy są poprawne. a) Jeżeli parametrem aktualnym jest zmienna to przekazywanie przez wartość i przez nazwę niczym się nie różnią. b) Z teoretycznego punktu widzenia instrukcja if jest zbędna, bowiem można zasymulować jej działanie za pomocą instrukcji while (być może z użyciem dodatkowych zmiennych). c) Jedynie w programach z wyjątkami da się zaobserwować różnicę między przekazywaniem parametrów przez referencję oraz przez wartość i wynik. d) Ponieważ przypisania dotyczą innych zmiennych, w programie x = f(1); y = g(2); printf("%d",x+y); w języku C można zawsze zmienić kolejność instrukcji nie zmieniając tego, co wypisane zostanie na ekranie. e) W poprawnym stylistycznie programie każda instrukcja powinna być opatrzona wyjaśniającym komentarzem. f) Ponieważ napisy w Pythonie są typami niezmiennymi, program x = "ala ma kota" x = "nieprawda, bo psa" spowoduje błąd czasu wykonania. 4