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