25-Comp-A4 Program Design and Data Structures · December 2014
Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)
Paper format. 98-Comp-A4 Program Design and Data Structures, December 2014 — 3 hours, closed book, no calculator permitted. Nine questions, each of equal weight (20 marks); candidates answer any six, so a complete paper is 120 marks. Pseudocode or any high-level language is accepted, and the examiner's note states explicitly that marking emphasises the operation of the program, not syntactic details. All nine questions are answered below, because the whole set is the more useful revision resource. Answers are given in C or C++ as the question dictates; each is compilable as written, but a clear, correctly reasoned pseudocode answer would earn the same marks.
Reference texts for this subject.
The Computer Engineering citation list is built around architecture and networking texts (Patterson & Hennessy, Tanenbaum, Mano); this subject is programming and data structures, so the works above are cited instead.
Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.
Given. A node type holding an integer coefficient, an integer exponent and a link; a list invariant of strictly decreasing exponents with positive coefficients; input pairs already sorted by exponent and terminated by the pair (0,0).
Find. Two functions: one that reads the terminated stream of pairs and returns the head of a newly built list; one that returns a newly built list representing the sum of two such polynomials.
Approach. Build by tail-appending so the input order is preserved in one pass; add by merging the two ordered lists in a single sweep, exactly as in the merge step of merge sort, emitting the higher exponent at each comparison and summing on a tie.
Check: the structure definition printed in the
question does not compile, and is corrected here. Inside an anonymous
struct, the name polynomial_node introduced by the
typedef is not yet in scope, so the next member has no
type to refer to. The self-referential form requires a struct tag. The
paper's own Note 5 states that marking emphasises the operation of the program
rather than syntax, so this is noted and fixed rather than treated as a change of
question. Everything below uses the corrected definition.
/* As printed in the question -- this does NOT compile: the tag
polynomial_node is not yet in scope inside the struct, and the struct
itself is anonymous, so the "next" pointer has no type to point at. */
typedef struct {
int coefficient;
int exponent;
polynomial_node *next;
} polynomial_node;
/* The correct self-referential form: give the struct a TAG and refer to
"struct polynomial_node" inside its own definition. */
typedef struct polynomial_node {
int coefficient;
int exponent;
struct polynomial_node *next;
} polynomial_node;
tail pointer makes each append $O(1)$ and
the whole build $O(n)$; prepending would be equally cheap but would reverse the
polynomial, breaking the invariant.scanf(...) == 2 as well means a
truncated input stream cannot spin the loop forever.
#include <stdio.h>
#include <stdlib.h>
/* Allocate one node, or fail loudly. */
static polynomial_node *new_node(int c, int e)
{
polynomial_node *n = malloc(sizeof *n);
if (n == NULL) {
fprintf(stderr, "out of memory\n");
exit(EXIT_FAILURE);
}
n->coefficient = c;
n->exponent = e;
n->next = NULL;
return n;
}
polynomial_node *get_polynomial(void)
{
polynomial_node *head = NULL, *tail = NULL, *node;
int c, e;
while (scanf("%d %d", &c, &e) == 2) {
if (c == 0 && e == 0) /* the (0,0) sentinel ends the input */
break;
node = new_node(c, e);
if (head == NULL) /* first node: it becomes the head */
head = node;
else /* otherwise append behind the tail */
tail->next = node;
tail = node; /* O(1) append keeps the input order */
}
return head;
}continue in the equal-exponent branch is therefore load-bearing.
(The question states coefficients are positive, so cancellation cannot arise
from its own data; guarding for it costs one line and makes the function safe
for the subtraction that any real polynomial package would add next.)next field accumulates the answer, the loop body
is uniform, and only head.next — a pointer to heap memory,
not to the local — escapes the function.polynomial_node *add_polynomials(polynomial_node *p1, polynomial_node *p2)
{
polynomial_node head; /* dummy: removes the "is it first?" test */
polynomial_node *tail = &head;
int c, e;
head.next = NULL;
while (p1 != NULL && p2 != NULL) {
if (p1->exponent == p2->exponent) {
c = p1->coefficient + p2->coefficient;
e = p1->exponent;
p1 = p1->next;
p2 = p2->next;
if (c == 0)
continue; /* the terms cancelled: emit nothing */
} else if (p1->exponent > p2->exponent) {
c = p1->coefficient; e = p1->exponent; p1 = p1->next;
} else {
c = p2->coefficient; e = p2->exponent; p2 = p2->next;
}
tail->next = new_node(c, e);
tail = tail->next;
}
/* At most one list still has terms; they are all of lower degree than
anything already emitted, so they append unchanged. */
for (; p1 != NULL; p1 = p1->next) {
tail->next = new_node(p1->coefficient, p1->exponent);
tail = tail->next;
}
for (; p2 != NULL; p2 = p2->next) {
tail->next = new_node(p2->coefficient, p2->exponent);
tail = tail->next;
}
return head.next; /* the dummy is a local; only its link escapes */
}| Item | Result |
|---|---|
| Corrected node definition | typedef struct polynomial_node { … struct polynomial_node *next; } polynomial_node; |
| (a) Build strategy | tail-append with a tail pointer, $O(n)$, order preserved |
| (a) Termination | the (0,0) sentinel, or a failed conversion |
| (b) Algorithm | single-pass merge of two ordered lists, dummy head |
| (b) Time / space | $O(m+n)$ time; one new node per term of the answer |
| (b) Worked example | $(5x^{4}+3x^{2}+7) + (2x^{4}+4x^{3}+6x^{2}) = 7x^{4}+4x^{3}+9x^{2}+7$ |
| (b) Operands after the call | unmodified and un-aliased |