Download Final Exam Instructions 15-122 Principles of Imperative Computation Penny Anderson

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Array data structure wikipedia , lookup

Binary search tree wikipedia , lookup

Quadtree wikipedia , lookup

Transcript
Final Exam
15-122 Principles of Imperative Computation
Penny Anderson
June 28, 2013
Name:
Andrew ID:
Instructions
• Turn off your phone, put all electronics in your bag, and leave it at the front of the room.
• This exam is closed-book with one sheet of notes permitted.
• You have 80 minutes.
• There are 6 problems on 20 pages.
• Read each problem carefully before attempting to solve it.
• Do not spend too much time on any one problem.
• Consider if you might want to skip a problem on a first pass and return to it later.
• There is an extra blank sheet at the end of the exam if you need more space.
• And don’t forget to KEEP YOUR COOL !
Max
Big-O
35
Bit-level operations
45
Arrays
40
Data structures and sorting
55
Spanning trees and union-find
35
C memory
40
Total:
250
Score
Please keep in mind that this is a sample solution, not a model solution. Problems admit
multiple correct answers, and the answer the instructor thought of may not necessarily be the
best or most elegant.
1
15-122
Final Exam, Page 2/20
Andrew ID:
1 Big-O (35 points)
Here is a list of complexity classes:
(a) O(n)
(b) O(1)
(c) O(n2 )
(d) O(n log n)
(e) O(2n )
(f) O(log n)
For each function f below, write the letter identifying the complexity class from the above list
that gives the tightest upper bound for f . For example, if f (n) = n2 , you would give (c), not
(e). If f does not belong to any of these complexity classes, write “none”. You may assume all
logarithms are to the base 2, if that makes you comfortable.
5
Task 1 f (n) = 3n2 + log n
Solution: c
5
Task 2 f (n) = n3 + 25n2
Solution: e
5
Task 3 f (n) = log 3n + 1
Solution: f
5
Task 4 f (n) = n2 + 2n + log n
Solution: e
5
Task 5 f (n) =
Pn
i=1 i
Solution: c
15-122
Final Exam, Page 3/20
Andrew ID:
Here is the definition of big-O:
Definition 1: g ∈ O(f ) if there is a constant c > 0 and a constant n0 such that for
every n ≥ n0 we have g(n) ≤ c ∗ f (n).
Informally we say that the class O(f ) provides an upper bound on the growth rate of g. Nevertheless, f itself need not be an upper bound for g.
In the lecture notes on big-O, several candidates were put forth for definitions of big-O, and
it was shown why they didn’t work. The first candidate was this wrong definition, which is
missing two features of the real definition:
Definition 2 (wrong): g ∈ O(f ) if for every n ≥ 0 we have g(n) ≤ f (n).
In the following two questions we will only think about integer values for function inputs. Be
as brief as possible in your answers; the right three words will suffice.
5
Task 6 Note that g(n) = 5n2 + 2n > n2 for n ≥ 0. So Definition 2 does not apply to g(n) and n2 .
Which feature of Definition 1 of big-O guarantees that g ∈ O(n2 )?
Solution: The constant c.
5
Task 7 Similarly, note that g(n) = log(n + 2) > n2 for 0 ≤ n ≤ 1. So Definition 2 does not apply
to g(n) and n2 . Which feature of Definition 1 of big-O guarantees that g ∈ O(n2 )?
Solution: The constant n0 .
15-122
Final Exam, Page 4/20
Andrew ID:
2 Bit-level operations (45 points)
This question is repeated from the midterm exam, but with some changes: please read it carefully!
For this question, the code you write should be C0 code, not C code; do not use any casts! As a
reminder, here is the C0 syntax for bit level operations:
&
|
^
<<
>>
~
logical and
logical or
logical exclusive-or
shift left
shift right
logical negation
Also, the C0 library functions that convert between characters and integers are
• int char_ord(char c)
• char char_chr(int n)
The following struct definition describes data that can be packed into one 32-bit integer: the
digit field must contain a number between 0 and 9 inclusive (four bits), and ASCII characters
are between 0 and 127 inclusive (7 bits).
struct id_info {
char c1; // any ASCII
char c2; // any ASCII
char c3; // any ASCII
char c4; // any ASCII
int digit; // must be
};
character
character
character
character
0-9
For this question, assume that we pack seven bits each for the four characters in order, starting
at the leftmost (high-order) bit; the rightmost low-order) four bits are used for the digit. For
example, if the four characters are “dcba” and the digit is 9, the encoding would look like this,
since the ASCII values for lower-case letters start at 0x61:
bit position 31. . . 25
24. . . 18
17. . . 11
10. . . 4
3 ...0
field
c1
c2
c3
c4
digit
encoding
110 0100 110 0011 110 0010 110 0001 1001
Assume that you have a pointer p to a struct id_info as described above, and the value in
the digit field is between 0 and 9 inclusive.
15
Task 1 Write the code to pack the fields of p into an integer variable id:
Solution:
id = char_ord(p->c1) << 25
| char_ord(p->c2) << 18 | char_ord(p->c3) << 11
| char_ord(p->c4) << 4 | p->c4;
15-122
15
Final Exam, Page 5/20
Andrew ID:
Task 2 Write the code to unpack an integer id into the struct pointed to by p:
Solution:
p->c1 = char_chr(id >> 25 & 0x0000007F);
p->c2 = char_chr(id >> 18 & 0x0000007F);
p->c3 = char_chr(id >> 11 & 0x0000007F);
p->c4 = char_chr(id >> 4 & 0x0000007F);
p->digit = id & 0x0000000F;
The ASCII codes are designed so that the code for an upper-case letter (e.g. ’A’) is derivable
from the code for the corresponding lower-case letter (e.g. ’a’). We number the bit positions of
a character from 6 to 0, left to right. The upper-case letter is derived from the lower-case letter
by turning off bit 5. For example, the code for ’a’ is 0x61, and the code for ’A’ is 0x41.
15
Task 3 Assuming you have an id packed into the integer id, write one line of code that will
convert the c2 field from upper case to lower case or vice-versa.
Solution:
id = id ^ 0x00800000;
15-122
Final Exam, Page 6/20
Andrew ID:
3 Arrays (40 points)
Once again, (Groundhog Day?) you are getting ready to hand in a solution to Image Lab, and
you’ve written some code to check that a given image is bilaterally symmetric across the yaxis. You’ve already implemented the image utility functions (the ones you need are described
on the last page of the exam, which you may tear off for reference if you like).
Here is the code you wrote for checking symmetry.
[ 1]
[ 2]
[ 3]
[ 4]
[ 5]
[ 6]
[ 7]
[ 8]
[ 9]
[10]
[11]
[12]
[13]
[14]
[15]
[16]
[17]
bool is_bilaterally_symmetric(pixel[] pixels, int width, int height)
//@requires is_valid_imagesize(width, heigth);
//@requires width*height <= \length(pixels);
{
for ( int i = 0 ; i < height ; i++ )
//@loop_invariant 0 <= i;
{
for ( int j = 0 ; j < width / 2 ; j++ )
//@loop_invariant 0 <= j;
{
if ( ! (pixels[get_index(i, j, width, height)] ==
pixels[get_index(i, width-j-1, width, height)]) )
return false;
}
}
return true;
}
15-122
Final Exam, Page 7/20
Andrew ID:
Complete the following argument that the calls to get_index are safe. You may use the comments that describe the behavior of the image utility functions. You may refer to earlier parts
of the argument by “2(a)”, etc.
The calls are safe if the preconditions of get_index are true. There are two calls:
get_index(i, j, width, height)
and
get_index(_____________________________________)
For the first call, the preconditions are (1) is_valid_imagesize(width, height),
and (2) is_valid_pixel(i, j, width, height)
(1) is the same as the first precondition of is_bilaterally_symmetric, so it must
be true.
For (2), we have
(a) 0 <= i by the first loop invariant;
(b) i < height by ________________________________________
(c) 0 <= j by ____________________________________________
(d) j < width / 2 by _____________________________________
(e) width / 2 < width because
width is positive by _________________________________________.
(f) so j < width by transitivity, (d) and (e).
For the second call the preconditions are
(3) is_valid_imagesize(________________________),
and (4) is_valid_pixel(_______________________________)
To prove (3) we have
To prove (4) we have
15-122
Final Exam, Page 8/20
Andrew ID:
Solution:
The calls are safe if the preconditions of get_index are true. There are two
calls:
get_index(i, j, width, height)
and
==========> get_index(i, width-j-1, width, height)
For the first call, the preconditions are (1) is_valid_imagesize(width, height),
and (2) is_valid_pixel(i, j, width, height)
(1) is the same as the first precondition of is_bilaterally_symmetric, so
it must be true.
For (2), we have
(a) 0 <= i by the first loop invariant;
(b) i < height by the first loop guard/line 5
(c) 0 <= j by the second loop invariant/line 9
(d) j < width / 2 by the second loop guard/line 8 and
(e) width / 2 < width because width is positive by is_valid_imagesize
(f) so j < width by transitivity, (d) and (e).
For the second call the preconditions are
(3) is_valid_imagesize(===> width, height<===), and
(4) is_valid_pixel(===>i, width-j-1, width, height<===)
To prove (3) we have the same argument as before, guaranteed by our first
precondition.
To prove (4) we have the same argument as (2) for i. For width-j-1 we
have
(a) j+1 <= width by 2(f) above and arithmetic;
(b) 0 <= width - (j+1) by (a) and arithmetic;
(c) 0 <= width - j - 1 by (b) and arithmetic;
(d) width - j - 1 < width by 0 <= j (2(c) above) and arithmetic.
0 <= width-j-1 because j < width / 2 < width (as argued in (2)).
4 Data structures and sorting (55 points)
Some of the data structures we have studied involve keys that have some ordering (alphabetical order, numerical order, or something similar). Among them are binary search trees and
heaps (priority queues).
Such structures can be used to sort data by their keys: the idea is to insert the data in any order
we please, and then to access it in order by key, placing the data in order in the output.
Here is a sketch of an implementation of bst_inorder for binary search trees:
15-122
Final Exam, Page 9/20
Andrew ID:
size_t tree_inorder(tree *T, elem* result, size_t next, size_t last) {
REQUIRES( next <= last );
if ( T == NULL ) return next;
else {
ASSERT( next < last );
// missing code here, see below
return next;
}
}
void bst_inorder(bst B, elem* result, size_t lower, size_t upper) {
REQUIRES( is_bst(B) );
REQUIRES( upper - lower >= bst_size(B) );
tree_inorder(B->root, result, lower, upper);
}
15
Task 1 In the code sketched above there is code missing in the else-clause of tree_inorder. The
missing code consists of the following three statements in some order:
(a) result[next] = T->data;
(b) next = tree_inorder(T->right, result, next+1, last);
(c) next = tree_inorder(T->left, result, next, last);
In what order should the statements be placed to produce a sorted array?
Solution: c, a, b
15-122
Final Exam, Page 10/20
Andrew ID:
Using our sort keys as priorities, we can implement the same idea using a priority queue
instead of a binary search tree. There’s no need to change the priority queue interface, since it’s
already designed to deliver elements in order of increasing priority values using pq_delmin.
Below is a sketch of the code to sort the elements of an array A, using a priority queue q. The
priority of an element is just the key that we want to sort on:
for ( size_t i = lower ; i < upper ; i++ ) {
ASSERT( lower <= i );
pq_insert(q, A[i]);
}
elem *result = xcalloc(upper - lower, sizeof(elem));
size_t next = 0;
while ( !pq_empty(q) ) {
// missing code here
}
10
Task 2 In the space provided below, write the code that is missing in the sketch above:
Solution:
result[next] = pq_delmin(q);
next++;
15-122
Final Exam, Page 11/20
Andrew ID:
Assume that key comparisons can be done in constant time, and give the asymptotic worstcase complexity of each of the three methods described below for sorting n elements. Briefly
explain your answer.
10
Task 3 (a) Inserting into a binary search tree and using bst_inorder.
P
Solution: O(n2 ). Since the tree may not be balanced n insertions could cost ni=1 i
operations, which is O(n2 ). The call to bst_inorder will visit each node in the tree
once, for a cost of O(n). So the overall cost is O(n2 ).
10
Task 4 (b) Inserting into an AVL tree and using bst_inorder.
Solution: O(n log n). Since the tree is balanced each insertion costs at worst O(log n)
operations, for a total of no more than O(n log n). Again the call to bst_inorder will
visit each node in the tree once, for a cost of O(n). So the overall cost is O(n log n).
10
Task 5 (c) Inserting into a priority queue implemented as a heap and then filling an array from
the heap as explained above.
Solution: O(n log n). Using a heap, each insert costs at worst O(log n) operations, for
a total of no more than O(n log n). There are then n pq_delmin operations, each with
a worst-case cost of (log n). So the overall cost is O(n log n).
15-122
Final Exam, Page 12/20
Andrew ID:
5 Spanning trees and union-find (35 points)
Recall Kruskal’s algorithm for finding a minimum spanning tree of a weighted undirected
graph: starting with a completely disconnected graph, repeatedly add a minimal-weight edge
that connects two distinct trees; stop as soon as the resulting graph is a spanning tree of the
original graph. For this question, you will work with the graph illustrated below.
F
H
2
2
G
3
2
4
3
C
2
3
D
2
3
A
10
E
3
B
Task 1 Give the edges of the spanning tree in the order they would be added by Kruskal’s algorithm, assuming that the edges have been sorted by weight as follows:
AC, BE, FG, EH, CF, AD, AF, BD, DE, GH, EG
Solution: AC, BE, FG, EH, CF, AD, BD
5
Task 2 Fill in the edges of the resulting spanning tree in the drawing below, showing the weight
of each edge.
F
H
G
C
E
D
A
B
15-122
Final Exam, Page 13/20
Andrew ID:
F
H
2
2
G
2
C
E
2
3
A
Solution:
D
2
3
B
15-122
Final Exam, Page 14/20
Andrew ID:
Suppose that in Kruskal’s algorithm we use a simple version of union-find to tell if two nodes
are in the same tree (i.e., in the same equivalence class). When we connect two trees by an
edge, we perform a union operation on the two corresponding equivalence classes. The union
operation simply uses the smaller number of the two canonical representives for the canonical
representative of the new class. Furthermore, it does not perform path compression.
Thus, union(A, i, j) works as follows:
1. Find the canonical representative A[i_rep] of i.
2. Find the canonical representative A[j_rep] of j.
3. If A[i_rep] < A[j_rep] set A[j_rep] = A[i_rep]; otherwise set A[i_rep] = A[j_rep].
20
Task 3 Show how the union-find algorithm will behave in the situation shown above by completing the table below with the contents of the array R of canonical representatives after
each edge is considered by Kruskal’s algorithm. Also show, for each edge considered,
the canonical representatives for the two vertices, and how many comparison operations
were needed to find them.
Assume that the nodes A . . . H are represented by the indexes 0 . . . 7, in that order.
We have filled in the first few steps for you. Again, assume that the edges have been
sorted in the order AC, BE, FG, EH, CF, AD, AF, BD, DE, GH, EG
edge
contents of array R
canonical
considrepreered
sentatives
0(A)
1(B)
2(C)
3(D)
4(E)
5(F)
6(G)
7(H)
(initial
0
1
2
3
4
5
6
7
contents)
AC
0
1
0
3
4
5
6
7
0, 2
BE
0
1
0
3
1
5
6
7
1, 4
FG
0
1
0
3
1
5
5
7
5, 6
EH
0
1
0
3
1
5
5
1
1, 7
compares
2
2
2
3
15-122
Final Exam, Page 15/20
Solution:
edge
considered
Andrew ID:
contents of array R
canonical compares
representatives
0(A)
0
1(B)
1
2(C)
2
3(D)
3
4(E)
4
5(F)
5
6(G)
6
7(H)
7
0
0
0
0
1
1
1
1
0
0
0
0
3
3
3
3
4
1
1
1
5
5
5
5
6
6
5
5
7
7
7
1
0, 2
1, 4
5, 6
1, 7
2
2
2
3
CF
0
1
0
3
1
0
5
1
0, 5
3
AD
0
1
0
0
1
0
5
1
0, 3
2
AF
0
1
0
0
1
0
5
1
0, 0
2
BD
0
0
0
0
1
0
5
1
1, 0
3
(initial
contents)
AC
BE
FG
EH
15-122
Final Exam, Page 16/20
Andrew ID:
6 C memory (40 points)
For each of the following code segments, state what is wrong with the code.
Look for errors involving pass-by-value versus pass-by-reference, using unallocated or uninitialized memory, dereference of an invalid pointer, freeing of an invalid pointer, and so forth.
We are not concerned with inefficiencies or just plain silliness; look for errors that will cause
undefined behavior.
You may assume that all appropriate libraries have been included.
8
Task 1 Recall that strcpy is a library function that copies its second “string” argument to its first.
int main() {
char* word = (char*) xmalloc(strlen("Aplus")*sizeof(char));
strcpy(word, "Aplus");
free(word);
return 0;
}
Solution: Space is not allocated for the string’s null terminator.
8
Task 2 struct player {
char* name;
int score;
};
typedef struct player player;
int main() {
player* noob = (player*) xmalloc(sizeof(struct player));
strcpy(noob->name, "Player");
noob->score = -1337;
free(noob);
return 0;
}
Solution: The code passes an uninitialized pointer to strcpy. No space has been
allocated for the name field.
15-122
8
Final Exam, Page 17/20
Andrew ID:
Task 3 void free_array(char** array, int num_elts) {
for (int i = 0; i < num_elts; i++) {
free(array[i]);
}
free(array);
}
int main() {
int n = 10;
char** A = (char**) malloc(n*sizeof(char*));
char* word = (char*) malloc(50*sizeof(char));
strcpy(word, "ace it ace it ace it");
for (int i = 0; i < n; i++) {
A[i] = word;
}
free_array(A, n);
}
Solution: All elements of A contain the same pointer, which is passed to free multiple times.
8
Task 4 int main() {
int** p = (int**) xmalloc(10 * sizeof(int*));
*p[9] = 42;
free(p);
return 0;
}
Solution: *p[9] dereferences an uninitialized pointer.
15-122
8
Final Exam, Page 18/20
Andrew ID:
Task 5 void allocate(int* array, int n) {
array = (int*) xmalloc(n*sizeof(int));
return;
}
int main() {
int* A;
allocate(A, 10);
free(A);
return 0;
}
Solution: In main, A points to unallocated memory (assigning to a function’s parameters has no effect outside that function).
15-122
Final Exam, Page 19/20
Andrew ID:
(If you need more space, you may write here. Clearly indicate which question and part you are
answering!)
15-122
Final Exam, Page 20/20
Andrew ID:
Image utility functions (tear off this page if you wish):
// Checks whether width and height are valid dimensions. To be valid
// dimensions, width and height must be strictly positive, and
// multiplying width*height must not cause overflow.
bool is_valid_imagesize(int width, int height)
;
// Given a width and height that are valid for an image, returns true
// if the given row and column represent a valid pixel location in an
// image of size width*height and false otherwise.
// I.e., 0 <= row && row < height && 0 <= col && col < width
bool is_valid_pixel(int row, int col, int width, int height)
//@requires is_valid_imagesize(width, height);
;
// Returns the index of a pixel in a one-dimensional array of pixels
// representing a two-dimensional image of size width*height, given
// the row and column of the pixel in the two-dimensional image.
int get_index(int row, int col, int width, int height);
//@requires is_valid_imagesize(width, height);
//@requires is_valid_pixel(row, col, width, height);
//@ensures 0 <= \result && \result < width*height;
;