 (20 points)
array singlylinked list linkedlist queue linkedlist stack
doublylinked list circular array queue array stack
For each of the following questions choose the best answer from the
above list. Assume that the size of an array is fixed once
it is created, and that its size cannot be changed thereafter.
Sometimes it may seem as though two or more choices would
be equally good. In those cases think about the operations that the
data structures support and choose the data structure whose operations
are best suited for the problem.
You may have to use the same answer for more than one
question:
 linkedlist queue The data structure you would use if you were writing
software for a call center that ensured that calls
are answered in a firstin, firstout order. You should
assume that you have to be able to store an unlimited
number of waiting callers.
 linkedlist stack The data structure you would use if you wanted to
store different purchase lots of an inventory item
(e.g., printers) and when you sold them, you want
to decrement the remaining quantity of the most
recently purchased lot. For example, if you
make 3 separate purchases of 20, 30, and 15 printers,
and you then sell 5 printers, you want to decrement the
lot of 15 printers so that it is now 10.
 array The data structure you would use if you had a presorted
set of data with a known size and you wanted to
use binary search to find whether or not certain
keys existed in the data (in binary search you
probe into the middle of the remaining data and then
eliminate either the bottom or upper half of the data
depending on the value of your key and the value of
the element at the middle of the data).
 circular, array queue The data structure that you would use in a router
to store and dispatch an
incoming set of message packets from the network if
you have a limited amount of memory to store the
packets (packets that cannot be stored because
there is not enough memory will be bounced back to the
sender). Packets should be dispatched to the next
router in the network in the order in which they are
received.
 singlylinked list The data structure that is easiest to use
if you need
to read and store an unknown number of data items, and
subsequently search this data structure for different
keys.
 (10 points) Consider the following set of declarations:
typedef struct {
int x;
char name[20];
char *address;
} FriendRecord;
FriendRecord *friend;
void *ptr;
char input[20];
Put an X next to any statement that is illegal, according to the compiler,
and explain why it is illegal:
 friend = ptr; illegal: you need to use a downcast to
assigned an untyped pointer to a typed pointer
 ptr = friend; legal: it is okay to assign a typed pointer
to an untyped pointer
 ptr>x = 20; illegal: even if ptr points to a
FriendRecord, this operation is illegal because an untyped pointer
does not have a known type and hence you cannot access any
member fields through an untyped pointer.
 strcpy(friend>name, input); legal
 friend>name = strdup(input); illegal: you cannot assign
a new pointer value to a statically declared character array.
 (15 points) State the BigO running times for the following
pieces of code and briefly justify your answer. A sample
answer might be:
O(n^{3}): the most time is spent in the three nested loops.
Each loop iterates n times, and each iteration of the innermost
loop requires a constant amount of time.
(a)
min = 1;
for (i = 0; i < n; i++) {
if (a[i] < min)
min = a[i];
}
printf("min = %d\n", min);

(b)
a = 10;
b = 20;
c = a + b;

(c)
for (i = 0; i < n; i++) {
if (array[i] > 0) {
sum = 0;
for (j = i; j < n; j++) {
sum += array[j];
}
printf("sum = %d\n", sum);
}
else
printf("array[%d] = %d\n", i, array[i]);
}


 O(n): There is one for loop that iterates n times and each iteration requires
a constant amount of time.
 O(1): There are three constant time statements executed in consecutive order, and
hence their time is additive, and constant.
 O(n^{2}): There is one outer loop that iterates n times. Each
loop iteration is dominated by the conditional, which in the worst
case always chooses the true branch. The for
loop in this branch iterates n times in the worst case and each iteration
requires a constant amount of time. Hence the true branch requires O(n)
time, and hence each iteration of the outer loop requires O(n) time. The
overall time is therefore O(n*n) = O(n^{2}).
 (10 points) Programs A and B are analyzed and found to have the runnng times
2^{N} and 1000N^{2}, respectively. Answer the following
questions (Note: you should not need a calculator to answer any of the
following questions):
 Which program has the better guarantee on the running time, for
large values of N (N > 10,000)? Why?
B: For large values of N, 1000N^{2} < 2^{N}
 Which program has the better guarantee on the running time, for
small values of N (N < 10)? Why?
A: For N < 10, 2^{N} < 1000N^{2}
 If you did not know the size of the input, which program would
you prefer? Why?
B: If you do not know the size of the input, you must assume the
worst case, which is that it will be fairly large. In that case
we prefer the program with the better bigO running time, and that
is B.
 (9 points) Suppose you have the following declaration for a list node:
struct node {
void *value;
struct node *next;
};
struct node *my_node, *successor;
Write a fragment of code that swaps my_node and its successor by
adjusting only the links (and not the data). The diagram below
shows the before and after order of the two nodes in the list.
You may declare
whatever temporary variables you need in order to perform the swap.
Before: ___________ _____________
< my_node < successor <
> > >
 
After: _____________ _____________
< successor < my_node <
> > >
 
The following diagram provides a guide to what happens in the code. The
numbered links shows the order in which the links are assigned new
values by the code. The numbered links are set by the numbered statement
in the code.
_____________ 5 ___________ 2 _____________ 3 _____________
 prev_node < my_node < successor < last_node 
 > > > 
 1  4  6 
struct node *prev_node = my_node>prev;
struct node *last_node = successor>next;
1) prev_node>next = successor;
2) successor>prev = prev_node;
3) last_node>prev = my_node;
4) my_node>next = last_node;
5) my_node>prev = successor;
6) successor>next = my_node;
 (16 points) Consider the following declarations and function:
push(Stack *s, int i); // push an integer i onto s
int pop(Stack *s); // pop an integer off s and return its value
bool isEmpty(Stack *s); // return true if the s is empty and false otherwise
Please note that I have simplified the above API from my stack library
to make it easier for you to deal with in this problem. In particular you
may assume that you have a stack of integers, rather than a stack of void *'s.
int mystery(Stack *stack) {
char token[5];
int x;
int a, b;
int result;
while (scanf("%s", &token) != EOF) {
if (sscanf(token, "%i", &x) == 1)
push(stack, x);
else if (strcmp(token, "+") == 0) {
if (!mystery1(stack, &a, &b))
return 1;
push(stack, a+b);
}
else if (strcmp(token, "*") == 0) {
if (!mystery1(stack, &a, &b))
return 1;
push(stack, a*b);
}
}
result = pop(stack);
if (isEmpty(stack))
return result;
else
return 2;
}
bool mystery1(Stack *stack, int *x, int *y) {
if (isEmpty(stack))
return false;
*x = pop(stack);
if (isEmpty(stack))
return false;
*y = pop(stack);
return true;
}
Suppose the input is:
3 2 + 4 * 3 5 * +
 What is the contents of stack after the second * is read and
processed?
Some of your entries may be empty. Fill the stack from bottom to top:
______________
 
 

 
 

 
 

 
 15 

 
 20 

 Once mystery has read the full input,
what does mystery return? 35
 Suppose the input were instead 3 2 + 4.
What would mystery return in this case? 2
 Suppose the input were instead 3 2 + *.
What would mystery return in this case? 1
 mystery
returns three different valuesresult, 1, or 2depending on the outcome
of its checks. How would your calling program interpret each of these
return values? That is, if your program had to print a message
explaining the meaning of the return value, what would it say. Be
concise (you may want to defer this question to the end of the test
because you might have to devise a couple sample input sequences to
figure it out and that could take some time).
 1: Too many operators
 2: Too many operands
 result: The value of the postfix arithmetic expression
 (20 points)
You are given two doubly linked lists, L1 and L2, of integers, both
sorted in ascending order. You should write a function named
setDifference(L1, L2) that deletes any element from L1 that
matches an element in L2. For
instance, if you are given the two lists:
L1: (6, 8, 10, 20, 25, 30, 41, 66)
L2: (3, 6, 10, 33, 38, 41, 55, 66, 78, 90)
then your modified L1 will be:
L1: (8, 20, 25, 30)
L2 will remain unchanged.
Note that after setDifference is finished, L1 contains only its
original elements that were not contained in L2.
Write the function setDifference(L1,L2) using my dllist library.
Here is some helpful information:
 L1 and L2 are pointers to Dllists.
 Assume that dll_val returns an int and not a void *. Hence
dll_val(node) will return the integer value of that node.
 The function does not return anything nor does it print anything.
It achieves its result by modifying the two lists.
 For maximum points, you should take advantage of the fact that
the elements of L1 and L2 are sorted in ascending order and traverse
each list only once. If you cannot
figure out how to do this, you can traverse L1 and L2
multiple times for 16 points.
 You need to show me your function declaration and definition.
Do not show me include files, statements to read data,
etc. Assume L1 and L2 have been created for you by the calling
function.
void setDifference(Dllist *L1, Dllist *L2) {
// pointers to traverse through L1 and L2
Dllist_Node *p1, *p2;
// pointer to save the node to which p1 points should this node need
// to be deleted
Dllist_Node *saveNode;
// the current integer values of the list elements pointed to by p1 and p2
int val1, val2;
p1 = dll_first(L1);
p2 = dll_first(L2);
while ((p1 != dll_sentinel(L1)) && (p2 != dll_sentinel(L2))) {
val1 = *(int *)dll_val(p1);
val2 = *(int *)dll_val(p2);
// delete from L1 any element that matches an element in L2
if (val1 == val2) {
saveNode = p1;
p1 = dll_next(p1);
dll_delete_node(saveNode);
}
else if (val1 < val2) {
p1 = dll_next(p1);
}
else { // val1 > val2
p2 = dll_next(p2);
}
}
}