ΕΙΣΑΓΩΓΗ ΣΤΟΝ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟ Ενδεικτικές Απαντήσεις Εξετάσεων Α' Περιόδου 2013 Θέµα 1 (α') Η απάντηση είναι λάθος. Αν χρησιµοποιήσουµε την µακροεντολή, για παράδειγµα, στην έκφραση 24/CUBE(2) η έκφραση αυτή θα αντικατασταθεί από την 24/(2)*(2)*(2) που θα δώσει αποτέλεσµα 48, λόγω της αριστερής προσεταιριστικότητας των τελεστών / και *, ενώ η επιθυµητή αντικατάσταση θα ήταν η 24/((2)*(2)*(2)) που θα έδινε σαν αποτέλεσµα το 3. Άρα, η µακροεντολή πρέπει να γραφεί ως: #define CUBE(X) ((X)*(X)*(X)) (β') char *mystrstr(char *s1, char *s2) char *ss1 = s1, *orig_s2 = s2; while (*s2!= '\0') /* Υπάρχουν ακόµα χαρακτήρες για έλεγχο στην s2 */ if (*s1 == '\0') /* Η s1 τελείωσε */ return NULL; /* εν υπάρχει ταίριασµα */ if (*s1 == *s2) /* Οι τρέχοντες χαρακτήρες ταιριάζουν */ s1++; /* Προχώρησε την s1 */ s2++; /* Προχώρησε την s2 */ else /* Οι τρέχοντες χαρακτήρες δεν ταιριάζουν */ s1 = ++ss1; /* Προχώρησε την αρχή πιθανού ταιριάσµατος στην s1 */ s2 = orig_s2; /* Η s2 πάλι από την αρχή */ /* Η s2 τελείωσε - βρέθηκε ταίριασµα */ return ss1; /* Επιστροφή της αρχής του ταιριάσµατος στην s1 */
(γ') Και οι δύο συναρτήσεις επιστρέφουν το άθροισµα των διαιρετών του ακεραίου n που τους δίνεται ως όρισµα. Η ds1 ελέγχει για πιθανούς διαιρέτες από το 1 έως το n, ενώ η ds2 από το 2 έως το n/2, έχοντας αθροίσει εξ αρχής στο τελικό αποτέλεσµα το 1 και το n ως διαιρέτες του n. ηλαδή, η ds2 κάνει περίπου τις µισές επαναλήψεις από την ds1. Με όρους πολυπλοκότητας, και οι δύο έχουν πολυπλοκότητα χρόνου O(n). Θα µπορούσαµε όµως να ελέγχουµε για διαιρέτες µέχρι την τετραγωνική ρίζα του n και, για κάθε διαιρέτη i που βρίσκουµε, να λαµβάνουµε υπόψη µας και τον "συµµετρικό" του διαιρέτη n/i (εκτός από την περίπτωση που το n είναι τέλειο τετράγωνο, οπότε όταν βρούµε την τετραγωνική του ρίζα ως διαιρέτη, θα τον λάβουµε υπόψη µόνο µία φορά, αφού ταυτίζεται µε τον "συµµετρικό" του. Μία συνάρτηση ds3 που υλοποιεί αυτόν τον αλγόριθµο είναι η εξής: int ds3(int n) int i, s; s = n+1; for (i = 2 ; i*i < n ; i++) if (n % i == 0) s += i + n/i; if (i*i == n) s += i; return s; Η πολυπλοκότητα χρόνου της συνάρτησης αυτής είναι O(n^(1/2)), αφού κάνει πλήθος επαναλήψεων περίπου ίσο µε την τετραγωνική ρίζα του n.
Θέµα 2 (α') int listlength(listptr list) int n = 0; while (list!= NULL) n++; list = list->next; return n; (β') Η συνάρτηση αντιστρέφει µία λίστα ακεραίων, χωρίς να µετακινήσει τους κόµβους της λίστας, απλώς αλλάζοντας κατάλληλα τους δείκτες προς τον επόµενο κόµβο κάθε κόµβου. Έστω η λίστα: 1000 1200 1300 +----+----+ +----+----+ +----+----+ 12 1200 --> 28 1300 --> 17 NULL +----+----+ +----+----+ +----+----+ Η συνάρτηση καλείται µε όρισµα τη διεύθυνση 1000 και επιστρέφει στο όνοµά της τη διεύθυνση 1300, έχοντας κάνει τις εξής αλλαγές στη λίστα: 1000 1200 1300 +----+----+ +----+----+ +----+----+ 12 NULL 28 1000 -+ 17 1200 -+ +----+----+ +----+----+ +----+----+ ^ ^ +--+------+ +--+
Θέµα 3 #include <stdio.h> int main(void) int maxnum, n, d, numb, digit, digits, sum, product; printf("please, give maximum number: "); scanf("%d", &maxnum); for (numb = 1 ; numb <= maxnum ; numb++) /* Για κάθε ακέραιο αριθµό στο διάστηµα [1,maxnum] */ digits = 0; n = numb; while (n) digits++; /* Μέτρησε το πλήθος των ψηφίων του αριθµού */ n /= 10; /* µέσω διαδοχικών διαιρέσεων µε το 10 */ sum = 0; /* Αρχικοποίησε το άθροισµα των δυνάµεων */ n = numb; while (n) digit = n % 10; /* Για κάθε ψηφίο του αριθµού */ product = 1; /* Βρες το αποτέλεσµα της ύψωσης */ for (d = 0 ; d!= digits ; d++) /* του ψηφίου σε δύναµη ίση µε */ product *= digit; /* το πλήθος των ψηφίων του αριθµού */ sum += product; /* Άθροισε το αποτέλεσµα */ n /= 10; if (sum == numb) /* Ο αριθµός είναι ναρκισσιστικός */ printf("%d ", numb); printf("\n"); return 0;
Θέµα 4 #include <stdio.h> #include <stdlib.h> int inboard(int, int, int); int main(int argc, char *argv[]) int i, j, ii, jj, k, m, n, br, pl, op; char **board; if (argc!= 3) n = atoi(argv[1]); if (n % 2) /* Μόνο για άρτια διάσταση */ pl = *argv[2]; if (pl == 'b') /* Ορισµός χρώµατος παίκτη και αντιπάλου */ op = 'w'; else if (pl == 'w') op = 'b'; else if ((board = malloc(n * sizeof(char *))) == NULL) for (i = 0 ; i < n ; i++) if ((board[i] = malloc(n * sizeof(char))) == NULL) printf("please, give the Othello board\n"); for (i = 0 ; i < n ; i++) for (j = 0 ; j < n ; j++) board[i][j] = getchar(); /* Ανάγνωση πλαισίου παιγνιδιού */ getchar(); for (i = 0 ; i < n ; i++) for (j = 0 ; j < n ; j++) if (board[i][j]!= '.') /* Αν το κελί είναι κατειληµµένο */ continue; /* πήγαινε στο επόµενο */ br = 0; for (k = -1 ; k <= 1 &&!br ; k++) /* Για κάθε πιθανή κατεύθυνση */ for (m = -1 ; m <= 1 &&!br ; m++) if (k == 0 && m == 0) /* Περίπτωση χωρίς κατεύθυνση */ continue; /* Πήγαινε στην επόµενη */ ii = i+k; /* Το αµέσως γειτονικό κελί του (i,j) στην */ jj = j+m; /* κατεύθυνση (k,m) είναι το (ii,jj) */ if (!inboard(n, ii, jj) board[ii][jj]!= op) continue; /* Αν το (ii,jj) είναι εκτός πλαισίου ή δεν είναι κατειληµµένο από αντίπαλο, πήγαινε στην επόµενη κατεύθυνση */ do /* Προχώρησε στην κατεύθυνση (k,m) */ ii += k; /* όσο είσαι εντός πλαισίου και το κελί */ jj += m; /* είναι κατειληµµένο από αντίπαλο */ while (inboard(n, ii, jj) && board[ii][jj] == op); if (inboard(n, ii, jj) && board[ii][jj] == pl) board[i][j] = '*'; /* Αν είσαι εντός πλαισίου και το */ br = 1; /* κελί είναι κατειληµµένο από τον παίκτη, σηµείωσε την ελεγχόµενη θέση ως νόµιµη και αγνόησε τις άλλες κατευθύνσεις */ printf("legal moves of player %c marked with *\n", pl); for (i = 0 ; i < n ; i++) for (j = 0 ; j < n ; j++) putchar(board[i][j]); putchar('\n'); for (i = 0 ; i < n ; i++)
free(board[i]); free(board); return 0; int inboard(int n, int i, int j) if (i >=0 && i < n && j >= 0 && j < n) return 0;